在加密貨幣世界中,“Not your keys, not your coins"的觀念深入人心。但權力越大,責任也越大。沒有中心化的服務提供商,使用者需要自己管理金鑰的整個生命週期,包括金鑰的生成、分發、儲存、使用、更新、作廢以及恢復。對小白來說可謂戰戰兢兢,時刻面臨金鑰丟失造成的資產或控制權丟失風險。這極大的損害了使用者體驗,影響區塊鏈的推廣和普及。如何設計安全的金鑰管理系統,實現足夠的冗餘,提供可靠的金鑰恢復能力,是區塊鏈行業面臨的一大挑戰。本文介紹一種基於智慧合約的社交金鑰恢復功能,它的核心思想來自social-recovery-using-address-book-merkle-proofs,並且在EIP2429中得以標準化。社交金鑰恢復社交金鑰恢復的思想由來已久。在傳統的web應用中,中心化的服務提供商會提供一系列的金鑰恢復途徑,比如:1. 使用者可以預留經過驗證的手機號,郵箱,密碼丟失時透過它們重設密碼;2. 在微信這類IM應用中,還可以提前設定幾個親密的聯絡人,用於在賬戶被凍結情況下的協助驗證解封。這些做法本質上都是提供了一個冗餘的多因子身份認證。在區塊鏈上,使用者的身份往往由公鑰代表,他的所有資料都和這個身份繫結,這些資料可能包括:1. 賬戶餘額;2. DAO裡面的角色和許可權,等等。私鑰一旦丟失,可以認為在當下的計算能力下是無法再恢復的。但可以設定一個新公鑰,繫結到丟失公鑰的資料上,或者是代理丟失公鑰的所有操作許可權。這隻能由智慧合約來實現。一個簡單的方案可以是這樣的:Alice持有一對金鑰 < secret_a, public_a> ,她的賬戶public_a裡面轉入了100個token。她為了防止金鑰丟失,將Bob,Charlie, Dave作為恢復金鑰的委託人,三者的公鑰分別為{public_b, public_c, public_d}。Alice還設定了一個域值,任意兩個人協助認證都可以重新設定公鑰。這樣就是一個最簡單的2/3鏈上門限金鑰恢復方案。有天Alice真的丟失了自己的金鑰,她重新生成了一對金鑰< secret_a_1, public_a_1> ,找Bob和Charlie幫助,二者分別使用各自的金鑰呼叫合約的恢復金鑰介面,提交兩筆交易tx1 = {(public_a, public_a_1, public_b), signature_of_bob}, tx2 = {(public_a, public_a_1, public_c), signature_of_charlie}。這樣合約驗證後透過了門限檢查,就可以將public_a的賬戶所有人替換為public_a_1,Alice成功找回了這筆資產啦!隱私保護?上面的方案存在幾個可能被攻擊的方面:1. Bob, Charlie, Dave三人看到自己作為恢復功能的委託人,可能會共謀私自替換掉金鑰,奪走這筆資產;2. 假設Bob, Charlie, Dave都是不作惡的好人,但由於他們的公鑰在區塊鏈是公開可查詢的,攻擊者可能選擇攻擊這三人中的薄弱環節,直到獲取足夠的私鑰;3. 攻擊者在知道Bob, Charlie, Dave身份的情況下,還可能模仿Alice的身份(使用AI模仿聲音、影片已經很成熟!),向他們發起恢復金鑰的請求;為了避免這些攻擊,不同的方法可以被採用,比如所有的金鑰恢復過程存在一個鎖定期(lock period),在鎖定期內Alice發現有人惡意重置公鑰,在她私鑰沒有丟失的情況下,可以主動終止金鑰恢復過程。當然這需要一些通知機制的配合。也可以再增加一些經濟上的懲罰措施,任何企圖恢復金鑰的人需要提前存一筆指定額度的資金,正常流程下在結束後會返還,但作惡情況下會被slash。但如果仔細思考,很容易意識到,這裡列舉的攻擊方法都由於Alice的協助恢復委託人賬戶在鏈上是公開可見的,缺乏隱私性。如果委託人的身份在鏈上是“加密”的,但同樣能執行後續的驗證過程,是否就能很好的降低風險呢?協助驗證的交易{(public_a, public_a_1, public_x), signature_of_x},本質上是需要證明該交易的簽名者是委託人集合的一份子,也就是成員證明,membership proof。但由於保護隱私的要求,我們在鏈上又不能儲存成員的明文。默克爾證明一種可行的方案是使用默克爾樹,這個區塊鏈裡面頻繁使用的資料結構,它不僅能夠提供防篡改的功能,也能作為成員證明的工具。
比如,上圖中的綠色葉節點是樹的一部分,提供其中三個黃色的節點雜湊,形成一條到根節點路徑,即一個合法的默克爾證明(merkle proof)。
其他方案,甚至是具有零知識性質的成員證明工具也可以作為思考的一個方向。
概念實現(PoC)
基於上面的討論,這裡給出一個保護隱私的鏈上金鑰恢復方案:
1. Alice本地儲存了Bob, Charlie, Dave等人的公鑰薄,以這些公鑰作為葉節點,生成一顆默克爾樹,她將根雜湊(root hash)提交到合約裡,同時設定恢復閾值等引數;
2. 在金鑰恢復過程中,Alice尋求Bob, Charlie的幫助,Bob對Alice的新公鑰進行簽名,Alice也生成了一個Bob的默克爾證明,提交交易tx1 = {public_a, public_a_1, public_b, signature_b, proof_of_bob_membership},合約驗證交易簽名合法性和證明有效性,並且記錄下bob的公鑰,類似重複,直到滿足閾值。
這個方案較好的解決了前面的攻擊可能:
1. Bob可能知道自己是委託人,但他並不知道其他委託人,則無法形成共謀;
2. 鏈上只有一個root hash,不會洩漏委託人的身份,則不會被定向攻擊;
3. 攻擊者在未獲得Alice本地的地址薄時也就無法偽造身份傳送恢復請求;
我基於substrate的social-recovery元件,開發了一個PoC,增加了隱私保護功能,程式碼參考:https://github.com/bitrocks/secret-social-recovery.