本文由塵埃科技整理編輯發布,請拖動至文章底部查看更多精彩內容

編輯|RR

1.6億美元不見了。


做市基金Wintermute在9月的一個早晨醒來,發現一個重要的錢包少了9位數(點擊閱讀: DeFi做市巨頭Wintermute,借FTX倒閉東風能重回巔峰嗎? )。


換誰誰不慌啊。


是什麼原因導致了這次被盜?


簡單說,是Vanity Address生成器糟糕的隨機性。黑客只是從頭重複了搜索迭代,直到他們重新創建了私鑰和公共地址。然後,數以百萬計的資金不翼而飛。


此外,還有一個關於Indexed Finance的故事,黑客在2021年10月盜取了1600萬美元,然後將被盜資金轉移到一個以0xba5ed…開頭的地址。他們不知道的是,這個Vanity Address也受到了困擾Wintermute的糟糕隨機性漏洞的影響,2022年9月,所有的錢都再次被盜,流向了另一個黑客。


這些天才開發者到底出了什麼問題,我們能從中學到什麼?



首先,什麼是Vanity Address? Vanity Address是指用戶創建的與其錢包或智能合約相關的公共地址。它可能以0x0000000開始,可能以0xdeadbeef開始,也可能是其他東西。它們受歡迎的原因有幾個:

1. gas優化。僅僅因為他們的EOA有一些前導零,Wintermute就節省了15,000美元的gas成本。聽起來很傻嗎?但這就是EVM的工作原理!如果你的地址裡有很多零,交易gas費用就會下降。



2. 協議的品牌效應。你知道1inch代幣合約的開頭是0x111111111嗎......?



3. 多鏈再現性。在我看來,這是重中之重,也是為什麼每個協議都應該在部署時使用一個Vanity Address。你的應用程序可以存在於15個不同的EVM鏈上,並且在任何地方都有相同的地址!這對開發者和用戶來說不是更容易嗎?



它在什麼時候是安全的?

以太坊地址有兩種類型:外部擁有賬戶(EOA)和智能合約賬戶。如果你用過MetaMask這樣的錢包,裡面的每個地址都有一個EOA。它被用來簽署消息和進行交易處理。與Uniswap合約這樣的智能合約賬戶相比,人們可以與之交互,但它不能在不被觸發的情況下自己採取行動。


很簡單——Vanity Address對EOA不安全,但對智能合約是安全的。

鴻溝


為什麼會這樣?我們將在下文中詳細解釋,但這取決於Vanity Address如何生成。對於EOA,你將在數以百萬計的私鑰中循環,直找到一個與公共地址相對應的、具有美感的地址。然而,私鑰控制著EOA中的資金,所以如果你用來迭代私鑰的隨機性被破壞了,那麼你的整個賬戶就毀了。另一方面,創建智能合約Vanity Address只需要通過公共種子進行迭代,而這些種子並不授予智能合約任何管理權限。

這就是Wintermute失敗而OpenSea成功的原因——使用不安全的軟件在不安全的內存中生成私鑰是不行的。但是用這種方式生成公有種子是完全沒問題的!所以EOA vanity是一條通往破產的道路,而智能合約vanity則是通往成功的道路。

為什麼協議需要Vanity Address


  • 更簡約的文檔。你可以在所有鏈上指向一個合約地址

  • 用戶可驗證。只有在字節碼完全逐個匹配的情況下,才會出現相同的合約地址

  • 開發者可驗證。由於相同的合約地址只出現在完全匹配的情況下,因此你可以在部署腳本中捕捉到棘手的小問題

  • 簡單的集成。其他協議可以將你的合約地址硬編碼到他們的多鏈代碼中,而不需要基於鏈上的if語句。

智能合約Vanity Address

有一種方法可以生成100%安全的vanity智能合約地址。使用哪種軟件並不重要,迭代技術是否公開洩露也不重要。這就是所謂的“CREATE2 Factory法”。這不僅提供了Vanity Address,也是確保你在多個鏈上擁有相同合約部署地址的萬無一失的方法。而且,它可以讓其他人在沒有任何私鑰共享或nonce假設的情況下,代表你無信任地部署代碼。


首先,簡單介紹一下智能合約地址的選擇方式。有兩個部署選項CREATE和CREATE2。當你直接從EOA部署智能合約時,默認流程是CREATE。該地址是通過將合約創建者地址與合約創建者nonce進行哈希運算來確定的。 nonce是指一個地址發送了多少交易,所以新的錢包是從0開始,每次發送一個新交易都會增加1。下面是CREATE部署的智能合約地址的神奇公式:

New_address = hash(sender, nonce)

雖不太常見但更有趣的是,下面是使用CREATE2部署的智能合約地址的公式:

new_address = hash(0xFF, sender, salt, byteccode)

前者看起來更簡單,對吧?但是,讓我們舉一個例子,看看與更強大的CREATE2流程相比,這種簡單性在哪些方面會產生不利影響。

粗心的Alice:多鏈會出問題

想像一下,一個名叫Alice的加密開發者創建了兩個智能合約:一個名為GriddleSwap的Uniswap分叉,以及一個名為ph00ts的NFT項目。這兩者都是不可變的獨立原語,這意味著不存在外部依賴關係或跨鏈橋風險。 Alice以nonce 0將GriddleSwap部署到以太坊,然後以nonce 1將ph00ts部署到以太坊。遺憾的是,Alice的注意力不夠集中,在將她的工作部署到第二大智能合約平台幣安智能鏈之前,她在加密推特上分了幾分鐘心。



她搞砸了部署順序,在GriddleSwap之前部署了ph00ts。因為智能合約地址完全取決於部署區塊鏈中的創建者地址和nonce,以太坊GriddleSwap的地址與BSC ph00ts的地址完全相同!雪上加霜的是,以太坊ph00ts的地址與BSC GriddleSwap的地址相同。這不僅僅會使終端用戶會感到困惑是。事實上,惡意部署者可能會濫用它來欺騙人們認為跨鏈合約行為是相同的。

細心的Alice:還是會有問題

即使Alice在部署時很認真,從不混淆她的nonce順序,也會有其他問題。如果Alice正確地部署到了以太坊和BSC上,但隨後在Polygon上進行了不相關的交易,那麼nonce 0已被使用了。她將永遠無法在那裡部署GriddleSwap,因為她的nonce已經增加了。因此,人們必須不惜一切代價保護部署者私鑰。如果Alice洩露了信息,惡意破壞者就可以進行不相關的交易。如果Alice丟失了它,她也失去了在新的鏈上再次部署到該地址的能力。這是一個永久性的漏洞,依賴於誠實的個人來保護私鑰。如果比特幣核心開發者都不能做到這一點,我們其他人又怎麼能做到呢?

CREATE2:解決方案


值得慶幸的是,有一種更好的方法可以跨鏈獲得一致的地址,而不依賴於秘密私鑰、不依賴於單一的部署者,並且在整個過程中可以抵抗部署者的錯誤。請記住用於查找使用CREATE2部署的智能合約地址的公式:

new_address = hash(0xFF, sender, salt, byteccode)

第一個參數0xFF是一個可以忽略的常數值。第二個參數(發件人地址)可以通過在大多數EVM鏈中選擇z0age的CREATE2 Factory部署0x0000000000FFe8B47B3e2130213B802212439497來保持一致。第三個參數是用戶選擇的salt,我們可以用它來找到一個Vanity Address,然後跨鏈保持不變。第四個是合約字節碼,它可以作為有用的完整性檢查,以確保我們在鏈上部署完全相同的功能。無論任何部署者做什麼,所有這四個參數都可以保持一致。


為什麼這樣做更好?與私鑰不同的是,部署者選擇的salt可以被公開!知道salt可以部署合約,但對合約資產或功能卻沒有任何控制權。因為它不綁定任何秘密信息,所以任何人都可以在不洩露或共享私鑰的情況下將合約部署到新的鏈上。字節碼參數還確保當且僅當字節碼相同時,這些新的無權限部署將具有相同的地址。因此,終端用戶無需進行詳細的代碼差異比較,就能得到更強的保證。

創建你自己的Vanity Address

你以為工作證明在以太坊合併後就完蛋了嗎?那些幫助比特幣區塊尋找帶有大量前導零的哈希原像的GPU能力,在為EVM智能合約找到帶有大量前導零的哈希原像方面也非常出色。來自OpenSea的z0age發現了一個簡單的設置方法來創建你自己的Vanity Address。

  1. Spin up a GPU Example instance using vast.ai that makes ~2 *billion* attempts per second and costs ~25 cents / hr:

    Image:nvidia/opencl

    GPU:1x RTX 3090

    Disk space to allocate:1.83 GB


  2. SSH in and install rust + create2crunch

    sudo apt install build-essential -y; curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y; source "$HOME/.cargo/ env"; git clone https://github.com/0age/create2crunch && cd create2crunch; sed -i 's/0x4/0x40/g' src/lib.rs


  3. 運行種子搜索。對於環境變量,INIT_CODE_HASH是是合約創建代碼的keccak256。 LEADING是你想要的前導零字節數,TOTAL是你想要的合約地址中的總零字節數。

export

FACTORY="0x0000000000ffe8b47b3e2130213b802212439497"; export CALLER="0x0000000000000000000000000000000000000000"; export INIT_CODE_HASH="0xabc...def"; export LEADING=5; export TOTAL=7; cargo run --release $FACTORY $CALLER $INIT_CODE_HASH 0 $LEADING $TOTAL


當z0age首次發布他的repo時,它能夠在上述vastAI硬件上每秒運行19億次嘗試。從那以後,向量化在一些OpenGL內核上瘋狂運行,我觀察到每秒有21.5億次嘗試。這意味著找到一個5前導零字節的地址將花費256^5/(2150000000 * 60)~= 8分鐘,找到一個6前導零字節的地址將花費256^6/(2150000000 * 3600)~= 36小時,而找到一個7前導零字節的地址將花費256^7/(2150000000 * 86400)~= 387天。請注意,一個字節等於兩個十六進製字符,因此一個5前導字節的地址將有10個零。當然,這種搜索可以完全並行化,而且隨著時間的推移,實際的成功概率將遵循泊松分佈。


部署CREATE2 Factory

精明的讀者可能已經註意到,CREATE2 Factory已經跨所有鏈在0x0000000000FFe8B47B3e2130213B802212439497上運行。這有點像雞生蛋還是蛋生雞的問題,一致的地址部署如何依賴於一致的地址部署?

當我最初了解這種方法時,我認為它只是一個由比我更聰明的人安全持有的私鑰。但實際上,它比這要強大得多! ENS創始人Nick Johnson的提出的“無密鑰交易”方法利用了這樣一個事實:你可以從任何交易簽名中恢復公共地址,而不需要知道簽署該簽名的相應私鑰。因此,人們可以創建一個交易(“部署CREATE2 Factory”),然後為其創建一個假簽名,例如僅由2組成的簽名。這個偽造的簽名有一個私鑰,但沒人知道它是什麼。但是我們可以恢復“無密鑰簽名”對應的公共地址,向其發送一些ETH,然後將簽名交易提交給mempool。儘管這種方法很抽象,但它是一個有效的交易,而且實際上是唯一可以從這個公共地址發出的有效交易。

結果呢?任何人都可以在沒有任何專有信息的情況下將factory部署到新的鏈上,同時防止惡意行為者造成損害。對於創建一個只能部署一次交易的單一用途的EOA來說,這是相當巧妙的技術。



這可以通過三個簡單的“forge cast”命令來完成。該字節碼太長,無法在此處複製,但你可以按照https://github.com/ProjectOpenSea/seaport/blob/main/docs/Deployment.md‌上的說明,在你選擇的任何鏈上無權限地部署CREATE2 Factory,當然,如果已經部署過了,就沒有必要再部署一次。

信息來源自substack ,略有修改,作者f oobar

塵埃科技

看牆外更多信息,推特賬號指路「Allrecode」


為Web3從業者建立內部鏈接,了解「重構研究院」

“商務合作”、“內容轉載”請直接在後台回復關鍵字


更多DAO、Web3、NFT、Metaverse

專業研究請關注塵埃科技旗下「老雅痞」


Web3知識點、乾貨類內容

請關注塵埃科技旗下「Allrecode重構」