14. 閃電網路的加密訊息傳輸
在本章中,我們將回顧閃電網路的_加密訊息傳輸_,有時也稱為Brontide 協定,它允許節點建立端對端加密通訊、身份驗證和完整性檢查。
|
本章的部分內容包含一些關於加密協定和閃電網路加密傳輸中使用的加密演算法的高度技術細節。如果你對這些細節不感興趣,可以跳過該部分。 |
14.2. 簡介
與原始的比特幣 P2P 網路不同,閃電網路中的每個節點都由唯一的公鑰標識,該公鑰作為其身份。預設情況下,此公鑰用於端對端加密網路內的_所有_通訊。在協定最低層預設啟用加密確保所有訊息都經過身份驗證、免受中間人(MITM)攻擊和第三方監聽,並確保在基本傳輸層面的隱私。在本章中,我們將詳細了解閃電網路使用的加密協定。完成本章後,讀者將熟悉加密訊息協定的最新技術,以及此類協定為網路提供的各種特性。值得一提的是,加密訊息傳輸的核心對於在閃電網路環境中的使用是_不可知的_。因此,閃電網路使用的自訂加密訊息傳輸可以應用到任何需要雙方之間加密通訊的環境中。
14.3. 通道圖作為去中心化公鑰基礎設施
正如我們在 在支付通道網路上路由 中學到的,每個節點都有一個長期身份,在路徑尋找過程中用作頂點的識別碼,也用於與建立洋蔥加密路由封包相關的非對稱加密操作。這個作為節點長期身份的公鑰包含在 DNS 引導回應中,也嵌入在通道圖中。因此,在節點嘗試連接到 P2P 網路上的另一個節點之前,它已經知道要連接的節點的公鑰。
此外,如果被連接的節點已經在圖中擁有一系列公開通道,那麼連接節點能夠進一步驗證該節點的身份。因為整個通道圖是完全經過身份驗證的,所以可以將其視為一種去中心化公鑰基礎設施(PKI):要註冊一個金鑰,必須在比特幣區塊鏈上開設一個公開通道,一旦節點不再擁有任何公開通道,它們就相當於被從 PKI 中移除了。
因為閃電網路是一個去中心化網路,所以不能指定任何一個中央機構來負責在網路中提供公鑰身份。取代中央機構的是,閃電網路使用比特幣區塊鏈作為 Sybil 攻擊緩解機制,因為在網路上獲得身份有實際成本:在區塊鏈中建立通道所需的費用,以及分配給通道的資本的機會成本。在基本上建立特定領域 PKI 的過程中,閃電網路能夠顯著簡化其加密傳輸協定,因為它不需要處理 TLS(傳輸層安全協定)帶來的所有複雜性。
14.4. 為什麼不用 TLS?
熟悉 TLS 系統的讀者可能會想:儘管現有 PKI 系統有缺點,為什麼不使用 TLS?確實,「自簽名證書」可以通過簡單地在一組節點之間斷言給定公鑰的身份來有效地繞過現有的全球 PKI 系統。然而,即使排除現有的 PKI 系統,TLS 也有幾個缺點促使閃電網路的創建者選擇了更緊湊的自訂加密協定。
首先,TLS 是一個已經存在了幾十年的協定,因此隨著傳輸加密領域的新進展而不斷演進。然而,隨著時間的推移,這種演進導致協定的規模和複雜性急劇膨脹。在過去幾十年中,TLS 中發現並修補了多個漏洞,每次演進都進一步增加了協定的複雜性。由於協定的歷史悠久,存在多個版本和迭代,這意味著客戶端需要理解許多先前的協定迭代才能與公共網際網路的大部分進行通訊,進一步增加了實作複雜性。
過去,在廣泛使用的 SSL/TLS 實作中發現了多個記憶體安全漏洞。在每個閃電節點中打包這樣的協定將增加暴露在公共點對點網路中的節點的攻擊面。為了增加整個網路的安全性並最小化可利用的攻擊面,閃電網路的創建者選擇採用 Noise 協定框架。Noise 作為一個協定,內化了幾十年來對 TLS 協定持續審查所學到的安全和隱私經驗教訓。在某種程度上,Noise 的存在使社群能夠有效地「重新開始」,使用一個更緊湊、更簡化的協定,同時保留 TLS 的所有額外優點。
14.5. Noise 協定框架
Noise 協定框架是一個現代、可擴展且靈活的訊息加密協定,由 Signal 協定的創建者設計。Signal 協定是世界上使用最廣泛的訊息加密協定之一。它被 Signal 和 WhatsApp 使用,這兩者加起來被全球超過十億人使用。Noise 框架是學術界和訊息加密協定行業幾十年演進的結果。閃電網路使用 Noise 協定框架來實作所有節點相互通訊時使用的_面向訊息_的加密協定。
使用 Noise 的通訊會話有兩個不同的階段:握手階段和訊息傳遞階段。在雙方可以相互通訊之前,他們首先需要達成一個只有他們知道的共享秘密,該秘密將用於加密和驗證相互發送的訊息。一種經過身份驗證的金鑰協議用於在雙方之間達成最終的共享金鑰。在 Noise 協定的背景下,這種經過身份驗證的金鑰協議被稱為_握手_。一旦握手完成,兩個節點就可以開始相互發送加密訊息。每次節點需要連接或重新連接時,都會執行握手協定的新迭代,確保實現前向保密性(洩露先前副本的金鑰不會危及任何未來的副本)。
因為 Noise 協定允許協定設計者從多種加密原語中選擇,例如對稱加密和公鑰加密,所以習慣上每種 Noise 協定的變體都有一個唯一的名稱。本著「Noise」的精神,協定的每種變體都選擇了一個源自某種「噪音」的名稱。在閃電網路的背景下,使用的 Noise 協定變體有時被稱為 Brontide。brontide 是一種低沉的隆隆聲,類似於在非常遠的地方雷暴時聽到的聲音。
14.6. 閃電網路加密傳輸詳解
在本節中,我們將分解閃電網路加密傳輸協定,並深入研究用於在節點之間建立加密、經過身份驗證和完整性保證通訊的加密演算法和協定的細節。如果你覺得這種程度的細節令人生畏,可以跳過本節。
14.6.1. Noise_XK:閃電網路的 Noise 握手
Noise 協定非常靈活,它提供了多種握手方式,每種都有不同的安全和隱私特性,供潛在的協定實作者選擇。深入探討每種握手及其各種權衡超出了本章的範圍。話雖如此,閃電網路使用一種稱為 Noise_XK 的特定握手。這種握手提供的獨特特性是身份隱藏:為了讓節點發起與另一個節點的連接,它必須首先知道其公鑰。從機制上講,這意味著回應者的公鑰實際上從未在握手過程中傳輸。相反,使用一系列巧妙的橢圓曲線 Diffie-Hellman(ECDH)和訊息驗證碼(MAC)檢查來驗證回應者的身份。
14.6.2. 握手符號和協定流程
每個握手通常由幾個步驟組成。在每個步驟中,一些(可能)加密的材料被發送給對方,執行一個 ECDH(或多個),握手的結果被「混合」到協定_副本_中。這個副本用於驗證協定的每個步驟,並有助於阻止一種中間人攻擊。在握手結束時,產生兩個金鑰 ck 和 k,用於在會話的整個生命週期中加密訊息(k)和輪換金鑰(ck)。
在握手的背景下,s 通常是一個長期靜態公鑰。在我們的情況下,使用的公鑰加密系統是橢圓曲線系統,使用 secp256k1 曲線實例化,這也在比特幣的其他地方使用。在整個握手過程中會生成多個臨時金鑰。我們使用 e 來表示新的臨時金鑰。兩個金鑰之間的 ECDH 操作表示為兩個金鑰的連接。例如,ee 表示兩個臨時金鑰之間的 ECDH 操作。
14.6.3. 高層概述
使用前面列出的符號,我們可以簡潔地描述 Noise_XK 如下:
Noise_XK(s, rs):
<- rs
...
-> e, e(rs)
<- e, ee
-> s, se
協定從回應者的靜態金鑰(rs)「預傳輸」給發起者開始。在執行握手之前,發起者要生成自己的靜態金鑰(s)。在握手的每個步驟中,所有透過線路發送的材料和發送/使用的金鑰都會逐漸雜湊到_握手摘要_ h 中。這個摘要在握手期間從不透過線路發送,而是在 AEAD(關聯資料認證加密)透過線路發送時用作「關聯資料」。關聯資料(AD)允許加密協定在密文封包旁邊驗證額外資訊。在其他領域,AD 可能是域名或封包的明文部分。
h 的存在確保如果傳輸的握手訊息的一部分被替換,對方會注意到。在每個步驟中,都會檢查 MAC 摘要。如果 MAC 檢查成功,那麼接收方知道到目前為止握手已經成功。否則,如果 MAC 檢查失敗,那麼握手過程就失敗了,應該終止連接。
協定還為每個握手訊息添加了一個新的資料:協定版本。初始協定版本是 0。在撰寫本文時,尚未建立新的協定版本。因此,如果節點收到 0 以外的版本,則應拒絕握手發起嘗試。
至於加密原語,SHA-256 用作選擇的雜湊函數,secp256k1 作為橢圓曲線,ChaChaPoly-130 作為 AEAD(對稱加密)構造。
Noise 協定的每個變體都有一個唯一的 ASCII 字串用於引用它。為了確保雙方使用相同的協定變體,ASCII 字串被雜湊成摘要,用於初始化起始握手狀態。在閃電網路的背景下,描述協定的 ASCII 字串是 Noise_XK_secp256k1_ChaChaPoly_SHA256。
14.6.4. 三幕握手
握手部分可以分為三個不同的「幕」。整個握手在發起者和回應者之間需要 1.5 個往返。在每一幕中,雙方之間發送一條訊息。握手訊息是一個固定大小的有效載荷,前綴是協定版本。
Noise 協定使用物件導向的符號來描述每個步驟的協定。在設定握手狀態期間,每一方都會初始化以下變數:
ck-
鏈結金鑰。這個值是所有先前 ECDH 輸出的累積雜湊。在握手結束時,
ck用於派生閃電訊息的加密金鑰。 h-
握手雜湊。這個值是握手過程中到目前為止發送和接收的_所有_握手資料的累積雜湊。
temp_k1、temp_k2、temp_k3-
中間金鑰。這些用於在每個握手訊息結束時加密和解密零長度 AEAD 有效載荷。
e-
一方的_臨時金鑰對_。對於每個會話,節點必須使用強加密隨機性生成新的臨時金鑰。
s-
一方的_靜態金鑰對_(
ls表示本地,rs表示遠端)。
給定這個握手加訊息會話狀態,我們將定義一系列函數來操作握手和訊息狀態。在描述握手協定時,我們將以類似於虛擬碼的方式使用這些變數,以減少協定中每個步驟解釋的冗長程度。我們將握手的_功能_原語定義為:
ECDH(k, rk)-
使用
k(一個有效的secp256k1私鑰)和rk(一個有效的公鑰)執行橢圓曲線 Diffie-Hellman 操作。返回值是生成點的壓縮格式的 SHA-256。
HKDF(salt,ikm)-
RFC 5869中定義的函數,使用零長度info欄位進行評估。所有
HKDF的呼叫都隱式地使用提取和擴展元件返回 64 位元組的加密隨機性。 encryptWithAD(k, n, ad, plaintext)-
輸出
encrypt(k, n, ad, plaintext)。其中
encrypt是使用傳遞的參數對ChaCha20-Poly1305(網際網路工程任務組變體)的評估,noncen編碼為 32 個零位元,後跟一個_小端序_ 64 位元值。注意:這遵循 Noise 協定慣例,而不是我們通常的端序。 decryptWithAD(k, n, ad, ciphertext)-
輸出
decrypt(k, n, ad, ciphertext)。其中
decrypt是使用傳遞的參數對ChaCha20-Poly1305(IETF 變體)的評估,noncen編碼為 32 個零位元,後跟一個_小端序_ 64 位元值。 generateKey()-
生成並返回一個新的
secp256k1金鑰對。其中
generateKey返回的物件有兩個屬性:.pub,返回表示公鑰的抽象物件;和.priv,表示用於生成公鑰的私鑰其中物件還有一個方法:
.serializeCompressed() a || b-
這表示兩個位元組字串
a和b的連接。
握手會話狀態初始化
在開始握手過程之前,雙方都需要初始化用於推進握手過程的起始狀態。首先,雙方需要構建初始握手摘要 h。
-
h = SHA-256(__protocolName__)
其中 __protocolName__ = "Noise_XK_secp256k1_ChaChaPoly_SHA256" 編碼為 ASCII 字串。
-
ck = h -
h = SHA-256(h || __prologue__)
其中 __prologue__ 是 ASCII 字串:
lightning。
除了協定名稱之外,我們還添加了一個額外的「序言」,用於進一步將協定上下文綁定到閃電網路。
為了完成初始化步驟,雙方將回應者的公鑰混合到握手摘要中。因為這個摘要在帶有零長度密文(僅 MAC)的關聯資料發送時使用,這確保了發起者確實知道回應者的公鑰。
-
發起節點混合回應節點的靜態公鑰(以比特幣的壓縮格式序列化):
h = SHA-256(h || rs.pub.serializeCompressed()) -
回應節點混合其本地靜態公鑰(以比特幣的壓縮格式序列化):
h = SHA-256(h || ls.pub.serializeCompressed())
握手幕
在初始握手初始化之後,我們可以開始握手過程的實際執行。握手由發起者和回應者之間發送的一系列三條訊息組成,以下稱為「幕」。因為每一幕是雙方之間發送的單一訊息,所以握手總共需要 1.5 個往返(每幕 0.5 個)。
第一幕完成增量三重 Diffie-Hellman(DH)金鑰交換的初始部分(使用發起者生成的新臨時金鑰),並確保發起者確實知道回應者的長期公鑰。在第二幕中,回應者將他們希望用於會話的臨時金鑰傳輸給發起者,並再次增量地將這個新金鑰混合到三重 DH 握手中。在第三幕也是最後一幕中,發起者將其長期靜態公鑰傳輸給回應者,並執行最終的 DH 操作將其混合到最終的共享秘密中。
第一幕
-> e, es
第一幕從發起者發送到回應者。在第一幕中,發起者嘗試滿足回應者的隱式挑戰。為了完成這個挑戰,發起者必須知道回應者的靜態公鑰。
握手訊息_恰好_ 50 位元組:1 位元組用於握手版本,33 位元組用於發起者的壓縮臨時公鑰,16 位元組用於 poly1305 標籤。
發送者動作:
-
e = generateKey() -
h = SHA-256(h || e.pub.serializeCompressed())新生成的臨時金鑰被累積到正在運行的握手摘要中。
-
es = ECDH(e.priv, rs)發起者在其新生成的臨時金鑰和遠端節點的靜態公鑰之間執行 ECDH。
-
ck, temp_k1 = HKDF(ck, es)生成一個新的臨時加密金鑰,用於生成認證 MAC。
-
c = encryptWithAD(temp_k1, 0, h, zero)其中
zero是零長度明文。 -
h = SHA-256(h || c)最後,生成的密文被累積到認證握手摘要中。
-
通過網路緩衝區向回應者發送
m = 0 || e.pub.serializeCompressed() || c。
接收者動作:
-
從網路緩衝區_精確_讀取 50 位元組。
-
將讀取的訊息(
m)解析為v、re和c:-
其中
v是m的_第一_位元組,re是m的接下來 33 位元組,c是m的最後 16 位元組。 -
遠端方臨時公鑰(
re)的原始位元組將使用金鑰的序列化壓縮格式編碼的仿射座標反序列化為曲線上的點。
-
-
如果
v是無法識別的握手版本,則回應者必須中止連接嘗試。 -
h = SHA-256(h || re.serializeCompressed())回應者將發起者的臨時金鑰累積到認證握手摘要中。
-
es = ECDH(s.priv, re)回應者在其靜態私鑰和發起者的臨時公鑰之間執行 ECDH。
-
ck, temp_k1 = HKDF(ck, es)生成一個新的臨時加密金鑰,稍後將用於檢查認證 MAC。
-
p = decryptWithAD(temp_k1, 0, h, c)如果此操作中的 MAC 檢查失敗,則發起者_不_知道回應者的靜態公鑰。如果是這種情況,則回應者必須在沒有任何進一步訊息的情況下終止連接。
-
h = SHA-256(h || c)接收到的密文被混合到握手摘要中。這一步確保有效載荷沒有被中間人修改。
第二幕
<- e, ee
第二幕從回應者發送到發起者。只有在第一幕成功的情況下,第二幕才會發生。如果回應者能夠正確解密並檢查第一幕結束時發送的標籤的 MAC,則第一幕成功。
握手_恰好_ 50 位元組:1 位元組用於握手版本,33 位元組用於回應者的壓縮臨時公鑰,16 位元組用於 poly1305 標籤。
發送者動作:
-
e = generateKey() -
h = SHA-256(h || e.pub.serializeCompressed())新生成的臨時金鑰被累積到正在運行的握手摘要中。
-
ee = ECDH(e.priv, re)其中
re是發起者的臨時金鑰,在第一幕中接收。 -
ck, temp_k2 = HKDF(ck, ee)生成一個新的臨時加密金鑰,用於生成認證 MAC。
-
c = encryptWithAD(temp_k2, 0, h, zero)其中
zero是零長度明文。 -
h = SHA-256(h || c)最後,生成的密文被累積到認證握手摘要中。
-
通過網路緩衝區向發起者發送
m = 0 || e.pub.serializeCompressed() || c。
接收者動作:
-
從網路緩衝區_精確_讀取 50 位元組。
-
將讀取的訊息(
m)解析為v、re和c:其中
v是m的_第一_位元組,re是m的接下來 33 位元組,c是m的最後 16 位元組。 -
如果
v是無法識別的握手版本,則回應者必須中止連接嘗試。 -
h = SHA-256(h || re.serializeCompressed()) -
ee = ECDH(e.priv, re)其中
re是回應者的臨時公鑰。遠端方臨時公鑰(
re)的原始位元組將使用金鑰的序列化壓縮格式編碼的仿射座標反序列化為曲線上的點。 -
ck, temp_k2 = HKDF(ck, ee)生成一個新的臨時加密金鑰,用於生成認證 MAC。
-
p = decryptWithAD(temp_k2, 0, h, c)如果此操作中的 MAC 檢查失敗,則發起者必須在沒有任何進一步訊息的情況下終止連接。
-
h = SHA-256(h || c)接收到的密文被混合到握手摘要中。這一步確保有效載荷沒有被中間人修改。
第三幕
-> s, se
第三幕是本節描述的經過身份驗證的金鑰協議的最後階段。這一幕作為結束步驟從發起者發送到回應者。第三幕_當且僅當_第二幕成功時執行。在第三幕中,發起者使用_強_前向保密性將其靜態公鑰傳輸給回應者加密,使用握手這一點累積的 HKDF 派生秘密金鑰。
握手_恰好_ 66 位元組:1 位元組用於握手版本,33 位元組用於使用 ChaCha20 流密碼加密的靜態公鑰,16 位元組用於通過 AEAD 構造生成的加密公鑰標籤,16 位元組用於最終認證標籤。
發送者動作:
-
c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())其中
s是發起者的靜態公鑰。 -
h = SHA-256(h || c) -
se = ECDH(s.priv, re)其中
re是回應者的臨時公鑰。 -
ck, temp_k3 = HKDF(ck, se)最終的中間共享秘密被混合到正在運行的鏈結金鑰中。
-
t = encryptWithAD(temp_k3, 0, h, zero)其中
zero是零長度明文。 -
sk, rk = HKDF(ck, zero)其中
zero是零長度明文,sk是發起者用於加密發送給回應者的訊息的金鑰,rk是發起者用於解密回應者發送的訊息的金鑰。生成最終的加密金鑰,用於在會話期間發送和接收訊息。
-
rn = 0, sn = 0發送和接收 nonce 初始化為 0。
-
通過網路緩衝區發送
m = 0 || c || t。
接收者動作:
-
從網路緩衝區_精確_讀取 66 位元組。
-
將讀取的訊息(
m)解析為v、c和t:其中
v是m的_第一_位元組,c是m的接下來 49 位元組,t是m的最後 16 位元組。 -
如果
v是無法識別的握手版本,則回應者必須中止連接嘗試。 -
rs = decryptWithAD(temp_k2, 1, h, c)此時,回應者已經恢復了發起者的靜態公鑰。
-
h = SHA-256(h || c) -
se = ECDH(e.priv, rs)其中
e是回應者的原始臨時金鑰。 -
ck, temp_k3 = HKDF(ck, se) -
p = decryptWithAD(temp_k3, 0, h, t)如果此操作中的 MAC 檢查失敗,則回應者必須在沒有任何進一步訊息的情況下終止連接。
-
rk, sk = HKDF(ck, zero)其中
zero是零長度明文,rk是回應者用於解密發起者發送的訊息的金鑰,sk是回應者用於加密發送給發起者的訊息的金鑰。生成最終的加密金鑰,用於在會話期間發送和接收訊息。
-
rn = 0, sn = 0發送和接收 nonce 初始化為 0。
傳輸訊息加密
在第三幕結束時,雙方都派生了加密金鑰,這些金鑰將用於在會話的剩餘時間內加密和解密訊息。
實際的閃電協定訊息封裝在 AEAD 密文中。每條訊息都以另一個 AEAD 密文作為前綴,該密文編碼了後續閃電訊息的總長度(不包括其 MAC)。
任何閃電訊息的_最大_大小不得超過 65,535 位元組。65,535 的最大大小簡化了測試,使記憶體管理更容易,並有助於緩解記憶體耗盡攻擊。
為了使流量分析更加困難,所有加密閃電訊息的長度前綴也被加密。此外,16 位元組的 Poly-1305 標籤被添加到加密的長度前綴中,以確保封包長度在傳輸中未被修改,並避免建立解密預言機。
線路上封包的結構類似於 加密封包結構 中的圖示。
前綴訊息長度編碼為 2 位元組大端序整數,總最大封包長度為 2 + 16 + 65,535 + 16 = 65,569 位元組。
加密和發送訊息
要加密閃電訊息(m)並發送到網路串流,給定發送金鑰(sk)和 nonce(sn),完成以下步驟:
-
設
l = len(m)。其中
len獲取閃電訊息的位元組長度。 -
將
l序列化為 2 位元組,編碼為大端序整數。 -
加密
l(使用ChaChaPoly-1305、sn和sk),得到lc(18 位元組)。-
nonce
sn編碼為 96 位元小端序數字。由於解碼的 nonce 是 64 位元,96 位元 nonce 編碼為 32 位元前導零後跟 64 位元值。 -
此步驟後 nonce
sn必須遞增。 -
零長度位元組切片作為 AD(關聯資料)傳遞。
-
-
最後,使用與加密長度前綴相同的程序加密訊息本身(
m)。讓這個加密的密文稱為c。此步驟後 nonce
sn必須遞增。 -
通過網路緩衝區發送
lc || c。
接收和解密訊息
要解密網路串流中的_下一條_訊息,完成以下步驟:
-
從網路緩衝區_精確_讀取 18 位元組。
-
設加密的長度前綴為
lc。 -
解密
lc(使用ChaCha20-Poly1305、rn和rk)得到加密封包的大小l。-
零長度位元組切片作為 AD(關聯資料)傳遞。
-
此步驟後 nonce
rn必須遞增。
-
-
從網路緩衝區_精確_讀取
l + 16位元組,設這些位元組為c。 -
解密
c(使用ChaCha20-Poly1305、rn和rk)得到解密的明文封包p。此步驟後 nonce
rn必須遞增。
閃電訊息金鑰輪換
定期更換金鑰並忘記先前的金鑰對於防止舊訊息在後來金鑰洩露的情況下被解密(即後向保密性)是有用的。
金鑰輪換對每個金鑰(sk 和 rk)_單獨_執行。當一方使用金鑰加密或解密 1,000 次後(即每 500 條訊息),該金鑰將被輪換。這可以通過在專用於該金鑰的 nonce 超過 1,000 時輪換金鑰來正確計算。
金鑰 k 的金鑰輪換按照以下步驟執行:
-
設
ck為第三幕結束時獲得的鏈結金鑰。 -
ck', k' = HKDF(ck, k) -
將金鑰的 nonce 重置為
n = 0。 -
k = k' -
ck = ck'
14.7. 結論
閃電網路的底層傳輸加密基於 Noise 協定,為閃電節點之間的所有通訊提供了強大的隱私、真實性和完整性安全保證。
與比特幣節點經常「明文」通訊(不加密)不同,所有閃電通訊都是點對點加密的。除了傳輸加密(點對點)之外,在閃電網路中,付款_也_被加密成洋蔥封包(跳對跳),並且付款詳情在發送者和接收者之間帶外發送(端對端)。所有這些安全機制的組合是累積的,並為去匿名化、中間人攻擊和網路監控提供了分層防禦。
當然,沒有安全是完美的,我們將在 閃電網路的 安全性與隱私 中看到這些特性如何被降級和攻擊。然而,閃電網路顯著改善了比特幣的隱私性。