天天看點

Schnorr 簽名方案和 BLS 簽名方案的全面對比

Schnorr 簽名算法最初是由德國密碼學家 Claus Schnorr 于 2008 年提出的,而來自區塊鍊協定公司 Blockstream 的密碼學家 GregoryMaxwell、PieterWuille 等人,則在 2018 年提出了一種名為 MuSig 的 Schnorr 簽名方案,這也是我們即将探索的簽名方案。而 BLS 簽名方案,最初是由斯坦福大學教授 DanBoneh 等人于 2001 年便提出的一種方案,目前則在 Boneh 教授等人的完善下,變得更适用于區塊鍊。總的來說,兩大簽名方案各有千秋,它們在不同的場景下都有各自的優勢。

目錄:

1、橢圓曲線數字簽名算法(ECDSA)

2、什麼是 Schnorr 簽名?

3、Schnorr 簽名的批量驗證

4、Schnorr 簽名的密鑰聚合

5、MuSig:由 Blockstream 提出的 Schnorr 簽名方案6、默克爾多重簽名(Merkle Multisig)

7、什麼是 BLS 簽名方案?

8、BLS 簽名的魔法

9、BLS 簽名方案的具體原理10、BLS 簽名的簽名聚合

11、BLS 簽名的密鑰聚合和 n-of-n 多重簽名

12、子群多重簽名方案(m-of-n multisig)

13、BLS 簽名可能的應用場景

14、BLS 簽名的弊端:配對效率低下15、結論

Blockstream 曾在 2018 年初的時候釋出了一份關于 MuSig 的論文,這是一種 Schnorr 簽名方案,總的來說,這種簽名方案的一些特征是非常好的,但其也存在着一些讓人讨厭的其他特征。

1 橢圓曲線數字簽名算法(ECDSA)

首先,我們需要明白,比特币目前使用的是 ECDSA 橢圓曲線數字簽名算法,要對消息 m 進行簽名,我們需對其進行哈希操作,并将此哈希視為一個數字:z = hash(m)。我們還需要一個随機或随機查找的數字 k。我們不喜歡信任随機數生成器(存在太多的故障,很多漏洞與糟糕的 RGN 有關),是以,我們通常會使用RFC6979,并根據我們的秘密和我們要簽名的消息,計算确定性 K 值。

使用私鑰 pk,我們可以為包含兩個數字的消息 m 生成簽名:r (随機點 R 的 x 坐标 = k×G) 和 s = (z+r⋅pk)/k。然後,使用我們的公鑰 P = pk×G,任何人都可通過檢查點 (z/s)×G+(r/s)×P 的 x 坐标等于 r,來驗證我們的簽名。

Schnorr 簽名方案和 BLS 簽名方案的全面對比

這個算法很常見,也很棒,但它也是可改進的。首先,簽名驗證包括反轉(1/s)和兩點乘法,這些操作的計算量非常大。在比特币中,每個節點都必須驗證所有交易。這意味着當你廣播一筆交易時,數千台計算機将不得不驗證你的簽名。而簡化驗證過程将是非常有益的,即使簽名過程會更加困難。

第二,每個節點必須分别驗證每個簽名。如果是 m-of-n 多重簽名交易節點,則可能需多次驗證相同的簽名。例如,具有 7-of-11 多重簽名輸入的交易将包含 7 個簽名,并且需要對網絡中的每個節點進行 7-11 次的簽名驗證。同樣,這樣的交易會占用大量的空間,你必須為此支付大量的費用。

2 什麼是 Schnorr 簽名

Schnorr 簽名的生成則略有不同,我們使用了一個點 R 和一個标量 s 來代替兩個标量(r,s)。與 ECDSA 相似的是,R 是橢圓曲線(R=K×G)上的一個随機點。簽名的第二部分計算略有不同 :

     s = k + hash(P,R,m) ⋅ pk. 這裡的 pk 是你的私鑰,而 P = pk×G 則是你的公鑰,m 是消息。然後可通過檢查 s×G = R + hash(P,R,m)×P 來驗證這個簽名。

Schnorr 簽名方案和 BLS 簽名方案的全面對比

這個方程是線性的,是以方程可互相加減,并且仍然有效,這就給我們帶來了幾大關于 Schnorr 簽名的好處。

3 Schnorr 簽名的批量驗證

要驗證比特币區塊鍊中的區塊,我們需確定區塊中的所有簽名都有效。如果其中一個是無效的,我們不會在乎是哪個無效的,我們隻會拒絕掉整個區塊。

對于 ECDSA 簽名算法,每個簽名都必須單獨驗證。也就是說,如果區塊中有 1000 個簽名,我們就需要計算 1000 次倒置和 2000 次點乘運算,總共約 3000 次繁重的計算任務。

而通過使用 Schnorr 簽名,我們可以将所有簽名驗證方程相加,進而節省一些計算能力。對于有 1000 個簽名的區塊而言,我們需驗證:

(s1+s2+…+s1000)×G=(R1+…+R1000)+(hash(P1,R1,m1)×P1+hash(P2,R2,m2)×P2+…+hash(P1000,R1000,m1000)×P1000)

這裡我們有一堆加法(在計算能力上幾乎是免費的)以及 1001 次點乘法。我們需要為每個簽名計算大約一次繁重的計算。

Schnorr 簽名方案和 BLS 簽名方案的全面對比

(圖 4: 兩個簽名的批驗證圖,由于驗證方程是線性的,隻要所有簽名都有效,幾個方程的和就有效。我們節省了一些計算能力,因為标量和點加法比點乘法容易得多)

4 Schnorr 簽名的密鑰聚合

我們希望讓自己的比特币保持安全,是以我們可能希望使用至少 2 個不同的私鑰來控制我們的比特币。比如說一個放在筆記本電腦或手機,另一個則放在硬體錢包 / 冷錢包。是以,當其中一個受到威脅時,我們仍然可以控制我們的比特币。

目前,它是通過 2-of-2 多重簽名腳本來實作的,這需要在交易中包含兩個單獨的簽名。而使用 schnorr 簽名,我們可以使用一對私鑰(pk1,pk2),并生成一個與共享公鑰 P=P1+P2=pk1×G+pk2×G 對應的共享簽名。要生成這個簽名,我們需要在每個裝置上選擇一個随機數(k1,k2),生成一個随機點 Ri=ki×G,将它們相加以計算一個公共哈希 (P,R1+R2,m),然後從每個裝置 (si = ki + hash(P,R,m) ⋅ pki) 中擷取 s1 和 s2。然後我們可以将這些簽名相加,并使用一對 (R, s) = (R1+R2, s1+s2) 作為我們對共享公鑰 p 的簽名。其他所有人都無法說出它是否是聚合簽名,它看起來與普通 schnorr 簽名完全相同。

這種構造有 3 個問題,第一,從使用者界面的角度來看,要進行交易,我們需要進行幾輪通信,計算公共 R,然後-簽名。有了兩個私鑰,隻需一次通路冷錢包就可以完成:我們在線上錢包上準備一個未簽名的交易,選擇 k1,将 R1=K1×G 與未簽名的交易一起記下。然後我們将這些資料傳送到冷錢包并簽名。因為我們已經有了 R1,是以我們可以一次性在冷錢包上簽署交易。從冷錢包中,我們得到了 R2 和 s2,并将其傳輸回線上錢包。線上錢包使用之前選擇的 (k1, R1) 簽署交易,結合簽名并廣播簽名交易。這與我們現在的情況非常相似,但一旦添加第三個私鑰,一切就會變得更加複雜。比方說,你有一筆财富,它是由 10 個私鑰控制的,它們存儲在世界各地不同的安全位置,然後,你需要進行一筆交易。目前,你隻需要浏覽所有這些位置一次,但如果你使用的是密鑰聚合,則需要執行兩次,以組裝所有 RI,然後簽名。在這種情況下,最好在不進行聚合的情況下保留單獨的簽名,然後我們就需要 3 輪通信:

  1. 選擇一個随機數 ​

    ​ki​

    ​ 和相應的 ​

    ​Ri=ki×G​

    ​,然後隻告訴每個人其哈希 ​

    ​ti=hash(Ri)​

    ​,這樣每個人都可以确定在學習了其他随機數之後你不會改變主意;
  2. 把所有的數字彙總起來,計算出共同的 R;
  3. 簽名;

第二個問題是已知的惡意密鑰攻擊。無論是在論文還是這篇文章中,都有很好的描述,是以我不想詳細讨論。其想法是,如果你的某個裝置被黑客攻擊(比如說,你的線上錢包),并假裝其公鑰是 (p1-p2),那麼它可以用它的私鑰 pk1 控制共享資金。一個簡單的解決方案是,在設定裝置時,需要使用相應的私鑰對公鑰進行簽名。

還有第三個重要問題。不能使用确定性 k 進行簽名。有一種簡單的攻擊方式,如果你使用确定性 K,它允許黑客獲得我們的私鑰。攻擊看起來會是這樣的:有人入侵了我們的筆記本電腦,并完全控制了兩個私鑰中的一個(例如 pk1)。我們可能覺得是安全的,因為我們的比特币需要來自 pk1 和 pk2 的聚合簽名。是以,我們嘗試像往常一樣進行交易,準備一個未簽名的交易和 R1 值,将它們轉移到我們的硬體錢包并在那裡簽名。然後傳回 (r2,s2) 和……我們的線上錢包發生了一些事情,它無法簽名和廣播。我們再次嘗試,但我們被黑的電腦這次使用了另一個随機值 R1'。我們再次與我們的硬體錢包簽署相同的交易,并将值 (r2,s2) 帶回我們被黑的電腦。然後,糟糕的事就發生了,我們的比特币就丢失了。

在這個攻擊中,黑客為同一筆交易獲得一對有效的簽名:(R1, s1, R2, s2) 和 (R1', s1', R2, s2'),這裡 R2 是相同的,但 R = R1+R2 和 R'=R1'+R2 是不同的,這意味着黑客可以計算我們的第二個私鑰:s2-s2'=(hash(P,R1+R2,m)-hash(P,R1'+R2,m))⋅pk2 and pk2=(s2-s2')/(hash(P,R1+R2,m)-hash(P,R1'+R2,m))。我發現這是密鑰聚合最不友善的特性:我們需要在任何地方使用好的随機數生成器來使用密鑰聚合。

5 MuSig:由 Blockstream 提出的 Schnorr 簽名方案

MuSig 方案解決了其中一個問題,它使得密鑰盜竊攻擊成為了不可能

。目标是将多個參與方 / 裝置的簽名和公鑰聚合到一個參與方 / 裝置,但不能證明你擁有與公鑰對應的私鑰。

聚合簽名對應于聚合公鑰。但是,我們不隻是将所有聯合簽名者的公鑰相加,而是将它們乘以某個因子。聚合的公鑰将是 P=hash(L,P1)×P1+…+hash(L,Pn)×Pn。這裡 L=hash(P1,…,Pn) 是一個取決于所有公鑰的公用數字。這種非線性特性可以防止攻擊者構造一個不好的公鑰,例如在惡意密鑰攻擊當中。盡管攻擊者知道自己的哈希 (L,Patk)×Patk 應是什麼,但他不能從中派生 Patk,這和從公鑰派生私鑰是相同的問題。

剩餘部分和前面的情況非常相似,為了生成簽名,每個聯合簽名者選擇一個随機數 ki,并與其他人共享 Ri=ki×G。然後将所有這些随機點相加到一個 R=R1+…+Rn,生成簽名 si = ki + hash(P,R,m) ⋅ hash(L,Pi) ⋅ pki。這個聚合簽名是 (R, s)=(R1+…+Rn, s1+…+sn),驗證方程與之前相同:s×G = R + hash(P,R,m)×P。

6 默克爾多重簽名(Merkle Multisig)

你可能會注意到,MuSig 和密鑰聚合都需要所有簽名者簽署一筆交易。但是,如果你要的是一個 2-of-3 的多重簽名呢?在這種情況下,是否可以使用簽名聚合,或者我們必須使用我們通常使用的 OP_CHECKMULTISIG 和單獨的簽名?

嗯,這是可能的,但是協定有一個小的改變。我們可以開發一個類似 ​

​OP_CHECKMULTISIG​

​ 的新 op 碼,它檢查聚合簽名是否與公鑰的默克爾樹中的特定項對應。

例如,如果我們使用帶有公鑰 p1、p2 和 p3 的 2-of-3 多重簽名,那麼我們需要為所有可使用的組合構造一個聚合公鑰的默克爾樹: (P1, P2), (P2, P3), (P1, P3),并将根放到鎖定腳本中。為了使用比特币,我們提供了一個簽名以及一個證明我們的公鑰在默克爾樹上的證據。對于 2-of-3 多重簽名,默克爾樹中隻有三個元素,證明将由兩個哈希組成,其中一個是我們想要使用的哈希,另一個則是其鄰哈希。而對于 7-of-11 的多重簽名,已經有 11!/7!/4!=330 種可能的密鑰組合,而證明需要 8 個元素。一般來說,證明中的元素數量幾乎與多重簽名種的密鑰數成線性關系 ( log2(n!/m!/(n-m)!)。

但是,有了公共密鑰的默克爾樹,我們不局限于 m-of-n 的多重簽名。我們可以用任何我們想要的公共密鑰制作一棵默克爾樹。例如,如果我們有一台筆記本電腦、一部電話、一個硬體錢包和一個恢複種子,我們可以建構一個結構,允許我們将比特币與一台筆記本電腦、一個硬體錢包、一部電話和一個硬體錢包或僅與一個恢複種子一起使用。隻有當你用分支和其他東西構造更複雜的腳本時,僅使用 OP_CHECKMULTISIG 會是不可能的。

Schnorr 簽名方案和 BLS 簽名方案的全面對比

                                    聚合公鑰的默克爾樹,不僅僅是 m-of-n 多重簽名

7 什麼是 BLS 簽名方案

BLS 簽名方案最初是由斯坦福大學教授 DanBoneh 等人于 2001 年就提出的一種簽名方案(原論文位址:https://www.iacr.org/archive/asiacrypt2001/22480516.pdf),而在 2018 年,Boneh 教授還與 IBM 研究機構的 ManuDrijvers 等人更新了這種簽名方案(https://eprint.iacr.org/2018/483.pdf)。

Schnorr 簽名方案是非常了不起的,如果我們做得對,我們可以将交易中的所有簽名和公鑰組合為一個密鑰和一個簽名,沒有人會發現它們對應于多個密鑰。區塊驗證也可以變得更快,因為我們可一次性驗證所有簽名。但它也存在着一些問題:

  1. 多重簽名方案需要多輪通信,這會使冷存儲變得非常煩人;
  2. 對于簽名聚合,我們必須依賴随機數生成器,我們不能像在 ECDSA 中那樣确定地選擇随機點 R;
  3. m-of-n 多重簽名方案是棘手的,我們需要制作一個公共密鑰的默克爾樹(merkle tree),對于大數的 m 和 n 來說,這顆默克爾樹可以變得相當大;
  4. 我們不能将區塊中的所有簽名組合為單個簽名;

BLS 簽名可修複上述所有問題,我們不需要随機數,區塊中的所有簽名都可以組合成單個簽名,m-of-n 類型的多重簽名非常簡單,我們不需要簽名者之間進行多輪通信。此外,BLS 簽名相比 Schnorr 簽名或 ECDSA 簽名要小 2 倍,其簽名不是一對,而是一個單曲線點。聽起來似乎很棒,對吧,讓我們看看它是如何工作的。

8 BLS 簽名的魔法

在開始之前,我們需要兩個新的結構:哈希到曲線(hashing to the curve)以及曲線配對(curves pairing)。

哈希到曲線(hashing to the curve)

通常對于 ECDSA 簽名以及 Schnorr 簽名,我們會哈希一則消息,并在簽名算法中使用此哈希作為一個數字。而對于 BLS 簽名,我們需要一個稍修改過的雜湊演算法,它直接哈希到橢圓曲線。最簡單的方法是像往常一樣哈希一則消息,并将結果視為點的 x 坐标。橢圓曲線(就像我們在比特币中使用的曲線)通常有 2²⁵⁶個點,而 SHA-256 雜湊演算法也給出了一個 256 位的結果。但是對于每個有效的 x 坐标,有兩個點具有正和負的 y 坐标(因為如果(x,y)在曲線 y²=x³+ax+b 上,則(x,-y) 也在曲線上)。這意味着我們的哈希有大約 50% 的機率為一些 x 找到兩個點,另有 50% 的機率無法找到。

Schnorr 簽名方案和 BLS 簽名方案的全面對比

      在有限域模 23 上定義的橢圓曲線 y²=x³+7 的玩具哈希例子。隻有一半的 X 坐标有點,這裡隻有第三次嘗試是成功的

要為任何消息找到一個點,我們可嘗試哈希幾次,方法是在消息中追加一個數字,并在失敗時遞增。如果 hash(m||0) 找不到點,我們嘗試 hash(m||1)、hash(m||2) 等等,直到最後得到一個比對的點。然後我們選擇兩個對應點中的一個,比如 y 較小的那個,然後我們就完成了。

曲線配對(curves pairing)

我們需要的另一件事是一個非常特殊的函數,它在一條曲線(或兩條不同的曲線)上取兩點 P 和 Q,并将它們映射至一個數字:

e(P, Q) → n.

我們還需要這個函數的一個重要屬性。如果我們有一些秘密數字 x 和兩點 P 和 Q,不管我們用哪個點乘以這個數字,我們都應得到相同的結果:

即:e(x×P, Q) = e(P, x×Q).

基本上,我們需要能夠在不改變結果的情況下交換兩個參數之間的點乘數。更普遍地說,所有這些互換都應産生相同的結果:

e(a×P, b×Q) = e(P, ab×Q) = e(ab×P, Q) = e(P, Q)^(ab)

我不想描述這個函數是如何精确工作的。基礎數學相當複雜,如果你想知道所有令人讨厭的細節,我建議你閱讀這篇文章和其中的參考資料。如果你想更深入一些,那這篇論文(https://crypto.stanford.edu/pbc/thesis.pdf)會比較适合你。目前,我們隻需要接受這種函數的存在,它們不會洩露關于我們的秘密數字 X 的任何資訊。

一個重要的注意項是,我們不能在這裡使用任何橢圓曲線(特别是标準比特币曲線 secp256k1 不起作用)。為了使這個函數高效和安全,我們必須使用來自“友好配對”家族非常特殊的曲線。

9 BLS 簽名方案的具體原理

現在我們有了建構 BLS 簽名所需的一切。和往常一樣,我們的私鑰是一些秘密數字 ​

​pk​

​,我們的公鑰是 ​

​P = pk×G​

​,我們要簽名的消息則是 ​

​m​

​。

為了計算簽名,我們将消息哈希到曲線 H(m) ,并将結果點乘以私鑰 : S = pk×H(m). 就是這樣了!沒有别的東西,沒有随機數,沒有額外的操作,隻有哈希乘以私鑰!我們的簽名隻是曲線上的一個單點,在壓縮序列化格式中隻需要 33 個位元組!

Schnorr 簽名方案和 BLS 簽名方案的全面對比

       BLS 簽名生成,為了獲得簽名,我們将消息的哈希值乘以私鑰

要驗證此簽名,可以使用我們的公鑰 P 并檢查:

e(P, H(m)) = e(G, S)

這為真,因為上面描述的配對函數的優良特性:

e(P, H(m)) = e(pk×G, H(m)) = e(G, pk×H(m)) = e(G, S)

Schnorr 簽名方案和 BLS 簽名方案的全面對比

BLS 簽名驗證 , 我們隻需要檢查公鑰和消息哈希是否映射到與曲線生成器點和簽名相同的數字

這個簽名方案既美觀又簡單,此外也有幾個非常好的功能,特别是對比特币而言。

10 BLS 簽名的簽名聚合

現在,讓我們組合區塊中的所有簽名!假設我們有一個包含 1000 筆交易的區塊,每筆交易都包含一個簽名 Si、一個公鑰 Pi 以及一個簽名為 mi 的消息。如果我們可以合并所有簽名,為什麼要存儲所有的簽名?畢竟,我們隻關心區塊中的所有簽名是否有效。聚合簽名将隻是區塊中所有簽名的總和:

S = S1+S2+…+S1000

要驗證區塊,我們需要檢查以下等式是否成立:

e(G, S) = e(P1, H(m1))⋅e(P2, H(m2))⋅…⋅e(P1000, H(m1000))

如果你仔細看,你會發現這是真的:

e(G, S) = e(G, S1+S2+…+S1000) = e(G, S1)⋅e(G, S2)⋅…⋅e(G, S1000) = e(G,pk1×H(m1))⋅…⋅e(G, pk1000×H(m1000)) = e(pk1×G, H(m1))⋅…⋅e(pk1000×G, H(m1000)) =e(P1, H(m1))⋅e(P2, H(m2))⋅…⋅e(P1000, H(m1000))

我們仍然需要知道所有的公鑰并計算 1001 個配對函數,但是至少區塊中的所有簽名隻占用 33 個位元組。簽名聚合可以由礦工完成,并節省區塊大量的空間。

11 BLS 簽名的密鑰聚合和 n-of-n 多重簽名

如果我們使用多重簽名位址,我們将使用不同的密鑰簽署相同的交易。在這種情況下,我們可以像在 Schnorr 簽名方案中那樣進行密鑰聚合,在 Schnorr 中,我們将所有簽名和所有密鑰組合到一對密鑰和一個簽名上。以常見的 3-of-3 多重簽名方案為例(對于任何數量的簽名者都可以這樣做)。

組合它們的一個簡單方法,是将所有簽名和所有密鑰添加到一起。結果将是簽名 S=S1+S2+S3 和密鑰 P=P1+P2+P3。很容易看出,同樣的驗證方程仍然有效:

e(G, S) = e(P, H(m))

e(G, S) = e(G, S1+S2+S3) = e(G, (pk1+pk2+pk3)×H(m)) = e((pk1+pk2+pk3)×G, H(m))= e(P1+P2+P3, H(m)) = e(P, H(m))

和 Schnorr 簽名方案一樣,運用 BLS 簽名需要保護自己免受流氓密鑰攻擊。我們可通過要求每個聯合簽名者證明他們具有的公鑰的私鑰(通過簽名他們的公鑰),或者我們可以在方案中添加一些非線性元素,使惡意密鑰攻擊成為不可能。我們不是簡單地将所有的密鑰和簽名相加,而是将它們乘以一個特定的數字,然後再相加:

S = a1×S1+a2×S2+a3×S3P = a1×P1+a2×P2+a3×P3

在這裡,簽名和密鑰的系數是根據簽名者的公鑰和所有其他公鑰來确定計算的:

ai = hash(Pi, {P1,P2,P3})

例如,它可以隻是簽名者公鑰和用于簽名的整個公鑰集的級聯:

ai = hash(Pi||P1||P2||P3).

同樣的驗證方程仍然有效。在證明中會有額外的系數 ai,但邏輯仍然存在。這個方案的好處在于,你不需要在裝置之間進行多輪通信。你隻需要知道誰是其他簽名者。這比 Schnorr 簽名的 3 輪多重簽名方案要簡單得多。它也不依賴任何随機性,它是一種完全确定的簽名算法。

12 子群多重簽名方案(m-of-n multisig)

通常,我們不會想用 n-of-n 的多重簽名方案,我們更喜歡使用 m-of-n (比如說 2-of-3)的多重簽名方案。我們不想因為丢了一把私鑰就把錢給弄丢。在這種情況下,最好使用密鑰聚合。有了 Schnorr 簽名方案,我們就可以通過使用公共密鑰的默克爾樹來做到這一點,它不是最有效的辦法,但很管用,壞處在于一旦 m 和 n 值很大,默克爾樹(merkletree)的大小就會成倍放大。

而對于 BLS 簽名方案,還有另一種方法。不過也沒那麼簡單,我們需要一個普通的哈希函數,它輸出一個數字 hash(x), 以及一個到曲線的哈希H(x)。當我們決定使用多重簽名時,我們還需要一個“設定”階段,但在此之後,我們不再需要通信,我們隻需要簽名來簽署任何數量的交易。

再次,我将使用一個簡單的例子,我們希望建構三個不同裝置上存儲密鑰的 2-of-3 多重簽名方案,但它可以擴充到任何值的 m 和 n。

設定階段

我們的每個裝置都有一個簽名者編号 i=1,2,3,代表其在集合中的位置,一個私鑰 pki 以及一個對應的公鑰 Pi = pki×G。這裡計算聚合公鑰的方式與之前完全相同:

P = a1×P1+a2×P2+a3×P3,

現在,每個裝置都需要簽名,而編号 i 是我們的聚合公鑰的成員(對于每個 i),聚合這些簽名并将結果儲存到相應的裝置上:MKi = (a1⋅pk1)×H(P, i)+(a2⋅pk2)×H(P, i)+(a3⋅pk3)×H(P, i)

這個簽名我們稱為“成員密鑰”,稍後我們将使用它進行簽名。每個成員密鑰都是消息 H(P,i) 的有效 n-of-n 簽名,這意味着:

e(G, MKi)=e(P, H(P,i))

記住這個方程,我們以後會用到的。它将用來證明我們是多重簽名方案的有效參與者。

簽名

現在假設我們隻想用密鑰 pk1 和 pk3 簽署一筆交易。我們生成兩個簽名 S1 和 S3:

S1 = pk1×H(P, m)+MK1, S3=pk3×H(P, m)+MK3

并将它們相加以獲得單個簽名和密鑰:

(S’, P’) = (S1+S3, P1+P3)

我在這裡寫為 P’ 和 S’,來強調這個密鑰和簽名隻由簽名者的一個子集簽名,它與 P 不同,P 是所有簽名者的聚合密鑰。要驗證這 3 個簽名中的 2 個,我們需要檢查:

e(G, S’) = e(P’, H(P, m))⋅e(P, H(P, 1)+H(P, 3))

我們記得成員密鑰 MK1 和 MK3 是由聚合密鑰 P 簽名的消息 H(P, 1) 及 H(P, 3) 的有效簽名,是以:

e(G, S’) = e(G, S1+S3)=e(G, pk1×H(P, m)+pk3×H(P, m)+MK1+MK3) =e(G, pk1×H(P,m)+pk3×H(P, m))⋅e(G, MK1+MK3)=e(pk1×G+pk3×G, H(P, m))⋅e(P, H(P, 1)+H(P,3))=e(P’, H(P, m))⋅e(P, H(P, 1)+H(P, 3))

就是這樣,要比 n-of-n 複雜一點,但仍然是可被了解的。

要實作這個多重簽名方案,我們需要将資金發送到與聚合公鑰 P 對應的位址,并表示我們至少需兩個簽名。在比特币腳本語言中,鎖定腳本可能如下所示:

OP_2OP_CHECK_BLS_MULTISIG

這裡,OP_2 告訴我們需要兩個密鑰來簽署消息。我們不會說任何地方總共就隻有 3 個簽名者,是以不能說它是 2-of-3 還是 2-of-100 多重簽名位址。為了使用這個輸出,我們需要在我們的案例 1 和 3 中提供參與簽名者的密鑰 P’、簽名 S’ 以及索引。解鎖腳本可能如下所示:

OP_1 OP_3

結合這些腳本,可以給我們提供所有必要的資訊。從 OP_1 和 OP_3,我們知道我們需要計算哈希 H(P, 1) 和 H(P, 3),然後我們就擁有了驗證交易所需的一切。這意味着對于任何 m 和 n,我們隻需要:鎖定腳本中的一個聚合公鑰 P;參與簽名者的一個聚合公鑰 P’一個聚合簽名;帶有簽名者索引的 m 數字;它非常緊湊,也很美!但它也并非完美…通常我們隻使用一次位址(我們使用像 bip32 這樣的密鑰派生來生成新的私鑰和位址),但是對于每一組新的私鑰,我們也需要一組新的成員密鑰。一種不用每次都運作設定階段的方法是生成一組密鑰,比如 1000 個密鑰,并獲得相應的成員密鑰。畢竟,它們隻有 32 位元組大小,然後,隻有在使用了所有 1000 個位址時,我們才需要再次運作設定階段。

14 BLS 簽名的弊端:

配對效率低下正如本文以及很多技術大佬在 Twitter 上所指出的,上面的讨論沒有談到一個重要的部分,而它可能是 BLS 簽名方案最大的缺陷。BLS 簽名的配對是很難的,我們認為神奇的函數 e(P, Q) 是有效和安全的,但事實并非如此。BLS 簽名驗證要比 ECDSA 簽名驗證的難度大上幾個數量級。對于具有 1000 筆交易的整個區塊的簽名聚合,仍然需要計算 1000 次配對,是以驗證一個區塊中的一個小簽名,可能比驗證 1000 個單獨的 ECDSA 簽名需要更長的時間。這裡 BLS 簽名能夠實作的唯一好處,在于我們可以在區塊中容納更多的交易,因為聚合簽名隻需要大約 32 個位元組。與 BLS 簽名不同,Schnorr 簽名是非常有效的,它們可以一起驗證,而且這個過程比 ECDSA 效率高 3 倍。另外,配對函數是複雜的,如果我們不夠小心,它會成為我們的敵人。一方面,我們希望配對能夠有效地、更快地驗證簽名,另一方面,我們不希望透露任何關于我們密鑰的資訊。這兩大需求互相競争,我們需要非常小心地選擇對配對友好的曲線。實際上有一種針對橢圓曲線加密系統的攻擊方法稱為 MOV 攻擊(以 Menezes,Okamoto 和 Vanstone 命名),它允許使用我們的魔法配對函數來降低系統的安全性。是以我們真的需要小心。然後問題就出現了:什麼對我們而言會更重要?

15 結論

Schnorr 簽名和 BLS 簽名方案都有自己的獨特之處,前者的主要缺點在于需要額外的通信回合,以及不适合較大值 m 和 n 的多重簽名方案,後者的驗證時間則是最大的弊端,兩者共同存在的好處都是可聚合簽名,節省區塊空間。就目前來看,Schnorr 簽名應用于比特币的可能性會更大,當然,方案都是可完善的,最終哪種協定能夠被采用,依然是一個未知數。

繼續閱讀