原文:「Vanity Addresses」 by foobar
編集: 一夜粥、DeFi のやり方
1 億 6,000 万米ドルが消え、ウィンターミュートは資金を失いました。ウィンターミュートは業界で最も抜け目のないマーケットメイク ファンドの 1 つです。9 月のある朝、ウィンターミュートの責任者が目を覚ますと、ウィンターミュートの重要な財布の 1 つが失われていることに気づきました。 9桁の資金を失っていた。では、Wintermute が盗まれた原因は何でしょうか?これは、バニティ アドレス ジェネレーターのランダム性が低いことが原因で発生します。ブラックハットハッカーは秘密鍵と公開アドレスのペアをゼロから総当たり攻撃し、大量の暗号資産が流出します。
また、Indexed Finance がハッキングされ、2021 年 10 月に 1,600 万ドルが盗まれ、盗まれた資金は 0xba5ed… で始まるアドレスに移動されたという話もあります。彼らが知らなかったことは、バニティ アドレスも Wintermute を悩ませていた悪質なランダム性の脆弱性の影響を受けており、2022 年 9 月にすべての資金が再び盗まれ、ハッキングされた別のウォレット アドレスに送られたということでした。泥棒は無慈悲です。
では、これらの才能ある開発者はどのような問題に遭遇し、私たちはそこから何を学べるのでしょうか?
左側は WETH 契約に使用される通常のアドレスです。右側は、MEV ロボット最適化のための先頭に 14 個のゼロを含むきれいなアドレスです。最も一般的なバニティ アドレスのタイプは、先頭に多数のゼロがあるタイプです。
まず、バニティアドレス(バニティアドレスとも呼ばれます)とは何でしょうか?バニティ アドレスは、ユーザーが自分のウォレットまたはスマート コントラクトに関連付けるために意図的に作成するパブリック アドレスを指します。おそらく 0x0000000 で始まるか、0xdeadbeef で始まるか、その他の通常のアドレスである可能性があります。人気の理由はいくつかあります。
1. ガスの最適化: Wintermute は、先頭にゼロが複数ある EOA アドレスを使用することで 15,000 ドルを節約しました。ばかばかしいと思われるかもしれませんが、これが EVM の仕組みです。アドレスにゼロがたくさんあると、トランザクションのガス料金が下がる可能性があります。したがって、先頭にゼロが多く含まれるスマート コントラクト アドレスを使用すると、ユーザーはコストを節約できるため、そのアドレスを操作するときに満足するでしょう。
イーサリアム イエロー ペーパーでは、先頭のゼロ アドレスがどのようにしてより安価なガスを可能にするかについて説明しています
2. 契約ブランド。 1インチトークンのコントラクトが0x111111111で始まることをご存知ですか...?
1インチトークンコントラクト
3. マルチストランドの再現性。私の意見では、これは最優先事項であり、すべてのプロトコルが展開にバニティ アドレスを使用する必要がある理由です。アプリケーションは 15 の異なる EVM チェーン上で稼働し、どこでも同じアドレスを持つことができます。これは開発者にとってもユーザーにとっても簡単ではないでしょうか?
それでは、どのような場合にきれいなアドレスが安全になるのでしょうか?
Ethereum アドレスには、外部所有アカウント (EOA) とスマート コントラクト アカウントの 2 種類があります。 MetaMask のようなウォレットを使用している場合、その中の各アドレスは EOA であり、メッセージに署名してトランザクションを処理するために使用されます。これを、Uniswap コントラクトなどのスマート コントラクト アカウントと比較してください。Uniswap コントラクトは、ユーザーが操作できるものの、トリガーされなければ独自のアクションを実行できません。要約すると、Good-number アドレスは EOA アカウントにとっては安全ではありませんが、スマート コントラクト アカウントにとっては安全です。
では、なぜそうなるのでしょうか?これについては以下で詳しく説明しますが、バニティ アドレスの生成方法によって異なります。 EOA アカウントの場合、見栄えの良いパブリック アドレスに対応する秘密キーが見つかるまで、何百万もの秘密キーを循環します。ただし、秘密キーは EOA アカウント内の資金を管理するため、秘密キーを通過するために使用するランダム性が損なわれると、アカウント全体が台無しになります。一方、スマート コントラクトのバニティ アドレスを作成するには、パブリック シードを通過するだけでよく、スマート コントラクトに対する管理権限は付与されません。
これが、Wintermute が失敗し、OpenSea が成功する理由です。安全でないソフトウェアを使用して安全でないメモリに秘密キーを生成するのは良くありません。しかし、この方法で公開シードを生成するのは非常に素晴らしいことです。したがって、適切な EOA アドレスは破産への道ですが、スマート コントラクトの適切なアドレスは成功への道です。
なぜプロトコルにはきれいなアドレスが必要なのでしょうか?
ドキュメントをより簡単に!すべてのチェーン上のコントラクト アドレスを指すことができます。
ユーザー認証可能!同じコントラクト アドレスは、バイトコードがバイトごとに一致する場合にのみ表示されます。
開発者が検証できる!同一のコントラクト アドレスは完全に一致する場合にのみ発生するため、展開スクリプト内の注意が必要な小さな変更を検出できます。
統合がさらに簡単に!他のプロトコルでは、chainId ベースの if ステートメントを使用せずに、コントラクト アドレスをマルチチェーンコードにハードコーディングできます。
注: これから詳細な取扱説明書を詳しく見ていきます。すべての要素を初めて組み合わせて、私たちは技術分野に深く入り込み、オンチェーンでスマート コントラクトを展開した経験を持つスマート コントラクト開発者をターゲットにしています。興味がある場合は読み続けてください。ただし、興味がない場合でも、最後には追加の技術的な課題があります (特典あり)。
スマートコントラクトの美しいアドレス
100% 安全なスマート コントラクト バニティ アドレスを生成する方法はあります。使用するソフトウェアに関係なく、反復テクノロジーが公的に漏洩しても問題ありません。これは「CREATE2 ファクトリ メソッド」と呼ばれ、きれいなアドレスを提供するだけでなく、複数のチェーンで同じコントラクト デプロイメント アドレスを確実に持つ確実な方法でもあります。また、他の人が秘密鍵の共有や nonce の仮定を行わずに、ユーザーに代わってコードをトラストレスにデプロイすることもできます。
まず、スマート コントラクト アドレスの選択方法について簡単に説明します。 CREATE と CREATE2 という 2 つのデプロイメント オプションがあります。 EOA から直接スマート コントラクトをデプロイする場合、デフォルトのプロセスは CREATE です。アドレスは、コントラクト作成者のアドレスをコントラクト作成者のノンスでハッシュすることによって決定されます。このナンスは、アドレスが送信したトランザクションの数を参照するため、新しいウォレットは 0 から始まり、新しいトランザクションが送信されるたびに 1 ずつ増加します。 CREATE によってデプロイされたスマート コントラクト アドレスの魔法の公式は次のとおりです。
new_address = ハッシュ(送信者、nonce)
あまり一般的ではありませんが、より興味深いのは、CREATE2 を使用してデプロイされたスマート コントラクト アドレスです。その式は次のとおりです。
new_address = ハッシュ(0xFF、送信者、ソルト、バイトコード)
前者のほうが簡単に思えますよね?ただし、より堅牢な CREATE2 プロセスと比較して、この単純さが有害となる可能性がある例を示してみましょう。
エアリー・アリス: マルチチェーンに問題があります
Alice という名前の暗号開発者が 2 つのスマート コントラクトを作成すると想像してください。GriddleSwap という Uniswap フォークと ph00ts という NFT プロジェクトです。これらはすべて不変の独立したプリミティブであり、外部依存関係やクロスチェーンブリッジのリスクがないことを意味します。アリスは nonce 0 を使用して GriddleSwap を Ethereum にデプロイし、次に nonce 1 を使用して ph00ts を Ethereum にデプロイします。残念ながら、アリスの集中力は短く、2 番目に大きいスマート コントラクト プラットフォームであるバイナンス スマート チェーン (BSC) に自分の作品をデプロイする前に、数分間暗号通貨 Twitter に気を取られていました。
おっと、展開順序を間違えました。
しかし、待ってください! 彼女はデプロイの順序を間違えて、GriddleSwap の前に ph00ts をデプロイしました。スマート コントラクトのアドレスは作成者のアドレスのみに依存しており、デプロイされたブロックチェーンでは、イーサリアム グリドルスワップは BSC ph00ts とまったく同じアドレスを持ちます。さらに悪いことに、イーサリアム ph00ts のアドレスは BSC グリドルスワップのアドレスと同じです。エンドユーザーが混乱するだろうと考えるのは控えめな表現です。実際、悪意のあるデプロイ担当者によって悪用されて、チェーン上のコントラクトの動作が同じであると人々を騙すことができます。これは、同じアドレスを与えられた場合、正当な仮定です。
気をつけろアリス:まだ問題はあるだろう
アリスがデプロイ時に注意し、ナンスの順序を決して混同しないとしても、他にも問題があります。 Alice が Ethereum と BSC に正しくデプロイされた後、Polygon 上で無関係なトランザクションを実行した場合、nonce 0 は使い果たされています。 nonce がインクリメントされているため、そこに GriddleSwap をデプロイすることはできません。したがって、デプロイヤーの秘密キーは、どんな犠牲を払ってでも保護する必要があります。アリスがそれを漏洩すると、悪意のある妨害者が無関係な取引を行う可能性があります。アリスがそれを失うと、新しいチェーンでそのアドレスに再度デプロイすることもできなくなります。これは永続的な脆弱性であり、秘密キーを保護するのは誠実な個人に依存します。ビットコインのコア開発者でさえそれができないなら、残りの私たちにはどうやってそれができるでしょうか?
解決策: CREATE2
ありがたいことに、チェーン全体で一貫したアドレスを取得するためのより良い方法があります。その方法は、秘密の秘密キーに依存せず、単一のデプロイヤに依存せず、途中でのデプロイヤのエラーに耐性があります。 CREATE2 を使用してデプロイされたスマート コントラクトのアドレスを見つけるための式を覚えておいてください。
new_address = ハッシュ(0xFF、送信者、ソルト、バイトコード)
最初のパラメータ 0xFF は無視できる定数値です。 2 番目のパラメーター (送信者アドレス) は、ほとんどの EVM チェーンで z0age の CREATE2Factory デプロイメント 0x0000000000FFe8B47B3e2130213B802212439497 を選択することで一貫性を保つことができます。 3 番目のパラメーターはユーザーが選択したソルトで、これを使用して適切なアドレスを見つけ、それをチェーン上で変更せずに維持できます。 4 番目はコントラクト バイトコードで、まったく同じ機能をオンチェーンにデプロイしていることを確認するための有用な健全性チェックとして機能します。単一のデプロイヤーが何を行っても、4 つのパラメーターはすべて同じままにすることができます。
これがなぜ優れているのでしょうか? 秘密キーとは異なり、デプロイ担当者が選択したソルトは公開できます。ソルトを知ることでコントラクトをデプロイできますが、コントラクトの資産や機能を制御することはできません。秘密情報をバインドしないため、誰でも秘密キーを公開したり共有したりすることなく、新しいチェーンにコントラクトをデプロイできます。また、バイトコード パラメータにより、バイトコードが同じ場合に限り、これらの新しいパーミッションレス デプロイメントが同じアドレスを持つことが保証されます。したがって、エンドユーザーはコードを詳細に変更することなく、より強力な保証を得ることができます。
さらに詳しい概要については、OpenZeppelin の人気科学記事を参照してください。
自分だけの美しい住所を作成しましょう
イーサリアムの合併後は Proof of Work (PoW) が役に立たなくなると思いますか?もう一度考えてみて!ビットコイン ブロックの先行ゼロが多数あるハッシュ プリイメージの検索に役立つ同じ GPU 機能は、EVM スマート コントラクトの先行ゼロが多数あるハッシュ プリイメージの検索にも優れています。 OpenSea の z0age は (この投稿の説明のおかげで)、独自のバニティ アドレスを作成するための簡単なセットアップを見つけました。
1. Vast.ai を使用して GPU サンプル インスタンスを起動します。これは 1 秒あたり約 20 億回試行され、1 時間あたり約 25 セントのコストがかかります。
画像:nvidia / opencl
GPU: RTX 3090 x 1
割り当てる必要のあるディスク容量: 1.83 GB
2. SSH で 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 はコントラクト アドレスに必要なゼロ バイトの合計数にする必要があります。
エクスポート FACTORY="0x00000000000ffe8b47b3e2130213b802212439497"; エクスポート CALLER="0x00000000000000000000000000000000000000000000"; エクスポート INIT_CODE_HASH="0xabc...def"; エクスポート LEADING=5; エクスポート TOTAL=7; cargo run --release $FACTORY $CALLER $INIT_CODE_HASH 0 $LEADING $TOTAL
z0age が最初にリポジトリをリリースしたとき、前述の VastAI ハードウェア上で 1 秒あたり 19 億回の試行を実行できました。それ以来、一部の OpenGL コアではベクトル化が異常に進み、1 秒あたり 21 億 5,000 万回の試行が行われたことを確認しました。これは、先頭に 5 つのゼロ バイトがあるアドレスを見つけるには 256^5/(2150000000 * 60) ~= 8 分かかり、先頭に 6 つのゼロ バイトがあるアドレスを見つけるには 256^6/(2150000000 * 3600) ~ = 36 時間かかることを意味します。先頭の 7 バイトのアドレスには 256^7/(2150000000 * 86400) ~= 387 日かかります。 1 バイトは 2 つの 16 進文字に等しいため、先頭の 5 バイトのアドレスには 10 個のゼロが含まれることに注意してください。もちろん、この検索は完全に並列化することができ、時間の経過に伴う実際の成功確率はポアソン分布に従います。
CREATE2ファクトリーをデプロイする
洞察力のある読者は、CREATE2 ファクトリがすべてのチェーンの 0x0000000000FFe8B47B3e2130213B802212439497 にすでに存在していることに気づいたかもしれません。これは鶏が先か卵が先かというような問題ですが、一貫したアドレスの展開は一貫したアドレスの展開にどのように依存するのでしょうか?
このアプローチについて最初に知ったとき、私はそれが私よりも賢い誰かが保持している単なる秘密鍵だと思いました (上記の「観察力のあるアリス」のシナリオ)。しかし、実際にはそれよりもはるかに堅牢です。ENS 創設者 Nick Johnson の「キーレス トランザクション」アプローチは、トランザクション署名に署名した対応する秘密キーを知らなくても、トランザクション署名からパブリック アドレスを復元できるという事実を利用しています。したがって、トランザクションを作成し (「create2 ファクトリをデプロイする」)、そのトランザクション用に 2 だけで構成される署名などの偽造署名を作成することが可能です。この偽造された署名の秘密鍵は存在しますが、それが何であるかは誰も知りません。しかし、「キーレス署名」に対応するパブリック アドレスを回復し、それにいくらかの ETH を送信し、署名されたトランザクションをメモリプールに送信することができます。このメソッドは不明瞭ですが、これは有効なトランザクションであり、実際、このパブリック アドレスから送信できる唯一の有効なトランザクションです。
その結果、悪意のある攻撃者による被害を防ぎながら、機密情報なしで誰でも新しいチェーンにファクトリをデプロイできるようになります。 1 つのトランザクションのみをデプロイできる単一目的の EOA を作成することは、非常に賢いテクニックです。
キーレストランザクション中に作成された特定のアドレスと契約
これは、3 つの単純な「forge Cast」コマンドで実現できます。バイトコードは長すぎてここにコピーできませんが、選択したチェーンで許可なく https://github.com/ProjectOpenSea/seaport/blob/main/docs/Deployment.md の手順に従うことができます。 CREATE2 Factory を簡単にデプロイできます。
もちろん、すでにデプロイされている場合は、再度デプロイする必要はありません。
補足: EIP-155 要件はひどいです
私の L1 ガバナンスの冒険をサポートするための簡単な試みですが、読み飛ばしていただいてもかまいません。 EIP-155は、2016年にVitalikによって提案された提案であり、リプレイ攻撃を防ぐために「チェーンID」の概念を導入しています。各チェーンには独自の一意の識別子 (イーサリアムの場合は 1、BSC の場合は 56、ポリゴンの場合は 137) があり、リプレイ攻撃を防ぐために署名されたトランザクションに含まれます。これはイーサリアムによってすぐに採用され、他のすべての EVM チェーンはこの提案に従いました。これは素晴らしいことですが、問題は、EIP-155 より前に取引を明示的に禁止することを最近決定した Evmos など、いくつかのチェーンが選択された場合に発生します。これにより、奇妙な理由で、Optimism が 2,000 万の OP トークンをmultisig (はい、また彼らです) は、Wintermute が存在せず、所有していると主張していますが、初期化されていないことを示しています。ただし、155 より前のトランザクションを無効にすると、CREATE2 ファクトリーや Seaport のような主要プロジェクトなど、一連のクロスチェーン デプロイメント全体が大幅に中断されます。これらのガバナンス提案は直ちにロールバックされるべきであり、このような保護の詳細はコンセンサス層ではなくウォレットから提供されるべきです。マルチチェーンが未来である場合、これらの不必要な制限は、トッププロジェクトがブロックチェーンに展開する際の大きな障害となるでしょう。
楽しいこと: 報奨金の展開
現在、https://delegate.cash は 7 つの異なる EVM チェーン (Ethereum、Polygon、Optimism、Celo、Avalanche、Fantom、Arbitrum) と、これらのチェーンに対応する 7 つのテストネットにデプロイされています。これらすべてのコントラクト アドレスは同じです: 0x00000000000076A84feF008CDAbe6409d2FE638B。
それで、これで十分ですか?いいえ、もっとチェーンが必要です。 delegatecash は依存関係のない独立したプリミティブであるため、複数のチェーンのリスクが事実上ゼロであることを意味します。これは純粋な利益です!したがって、delegatecash スマート コントラクトを新しいチェーンと対応するテストネットにデプロイして検証した最初の 5 名に、100 USDC ボーナスを授与します。
ここでは、オープンソース リポジトリのデプロイメント スクリプトを使用する必要があります。 CREATE2 ファクトリが存在しない場合は、これをデプロイする必要がある場合があります。Etherscan の検証を忘れないでください。ぜひ導入して、体験学習をお楽しみください。
