EIP-7702凄すぎ説

こんにちは。この記事は以下の続きのような感じです。

前の記事で、EIP-7702はブロックチェーン玄人にとっては有力なオプションで、既存または新規のEOAに code をセットしてAccount Abstractionを含むコントラクトウォレット(e.g. smart account)のメリットを享受するといい、しかしブロックチェーンにもセキュリティにも疎い初心者ユーザには使いづらいのではないか? 引用すると

実際にこのユーザ群にとって良い選択肢である一方で、無知なユーザに必要以上の権限委譲をさせてしまう危険性を孕んでいると感じました。ウォレットやdAppの提供者は、ユーザのEOAに「この code をセットしませんか」と促すことができます。その code はユーザが理解していない副作用を持つかもしれません。また、セットできる code は一つなので、ウォレット提供者はともかくdAppがそれをセットするのは、他のdAppも違う code をセットさせたいのではないか? その code にユーザが乗り換えようとしたとき、最初の code とデータに互換性はあるのか?

のような懸念を書きました。しかし、さらに考えを進めたり最近のサイトをいくつか見ているうちに、思った以上に簡単で、セキュアで、コストも低いウォレット管理が初心者にも提供できるのではないかと思うに至りました。もはや Smarter EOA という標題を超えて、EOAを全く意識しないことも可能そうです。例として、使う技術は以下が考えられます。

上記の殆どは以下2つのサイトで使用されています。

下のサイトはほぼ間違いなく上のサイトのコード(ソースコードリンク)を参考にして作られていますが、まず上のサイトは以下のログイン(Connect Wallet)、トランザクション体験を提供しています。

  1. ランダムなEthereumの秘密鍵( secp256k1 ECDSA)をフロントエンドで生成。EOAアドレスAが導出される

  2. EIP-7702で、そのアドレスAの code に、既にデプロイされているコントラクトウォレット実装をセット

  3. Passkey + WebAuthnを使って、P-256( secp256r1 ECDSA )の秘密鍵、公開鍵(以下 es256PubKey )を生成。256の後が kr かが上と異なることに注意。秘密鍵自体は例えばMacOSで言うとKeychainに保存され、値を見ることはできないが任意のメッセージに署名することができる。コントラクトウォレットの初期化プロセスとして es256PubKey に他のコントラクト実行の権限を与える。コードは以下の authorize execute 関数を参照。RIP-7212は、 以下の P256.verify(digest, signature, key.publicKey) の、この実行をしていいかを検証する部分を安価にするための仕組み

    1. 背景として、P-256/ES256による署名はPasskeyのベースであるFIDO2/WebAuthnのデフォルト署名形式であり、Ethereumにおけるデフォルト署名形式と互換性がありません
    /// @notice Authorizes a new public key.
    /// @param publicKey - The public key to authorize.
    /// @param expiry - The Unix timestamp at which the key expires.
    function authorize(
        ECDSA.PublicKey calldata publicKey,
        uint256 expiry
    ) public returns (uint32 keyIndex) {
        if (msg.sender != address(this)) revert InvalidAuthority();

        Key memory key = Key({
            authorized: true,
            expiry: expiry,
            publicKey: publicKey
        });
        keys.push(key);
        emit Authorised();
        return uint32(keys.length - 1);
    }
    // /// @notice Executes a set of calls on behalf of the Authority, provided a P256 signature over the calls and a public key index.
    // /// @param calls - The calls to execute.
    // /// @param signature - The P256 signature over the calls: `p256.sign(keccak256(nonce ‖ calls))`.
    // /// @param keyIndex - The index of the authorized public key to use.
    // /// @param prehash - Whether to SHA-256 hash the digest.
    function execute(
        bytes memory calls,
        ECDSA.Signature memory signature,
        uint32 keyIndex,
        bool prehash
    ) public {
        bytes32 digest = keccak256(abi.encodePacked(nonce++, calls));
        if (prehash) digest = sha256(abi.encodePacked(digest));

        Key memory key = keys[keyIndex];
        if (!key.authorized) revert KeyNotAuthorized();
        if (key.expiry > 0 && key.expiry < block.timestamp) revert KeyExpired();

        if (!P256.verify(digest, signature, key.publicKey)) {
            revert InvalidSignature();
        }
        emit Executed();
        multiSend(calls);
    }

この仕組みが凄いのは、ステップ1で作られたランダムなアドレスAの秘密鍵が、ステップ3終了時点でもう破棄可能で、これ以降、そのウォレットを使ってなんらかのトランザクションを起こしたいときにはEOAを気にすることなくPasskeyによる認証をすれば良い。多くのデバイスでは指紋認証や顔認証など手軽さ・簡単さは満点、セキュリティについては少なくとも鍵の保管場所という意味では十分な強度を手に入れていることです。

しかしながら、下のサイトについては上のようにオンチェーンでのES256/P-256署名検証はされていません(トランザクション例)。何故かと言うと下のサイトはEthereum Sepoliaテストネットで動いており、そこではRIP-7212は利用できず、オンチェーンでの検証はコスト大幅高に繋がるためです。このプロポーザルは元々EIP-7212、つまりEthereumを含む殆ど全てのEVMチェーンにて利用できることを想定して提案されたようですが、途中でL1に比べ変更が容易であるRollupチェーンでの利用を目指すRIPに移行したようです。

  • secp256k1(Ethereum標準)の署名からアドレスを復元するコストは3,000gas以下程度

  • RIP-7212 を用いたP-256( secp256r1 )のそれは数千~数万 gas程度

  • secp256r1 の検証をSolidityで実装した場合: 数百万gas程度

    • Daimoプロジェクトによる実装が33万gasを達成したとされたが長い間更新されていない……?

RIP-7212 もしくは他のなんらかの手段(例えばオフチェーンでの検証 + ZKなど……?)で安価な検証ができたとすると、指紋認証だけで、webブラウザ上でウォレットを作成してその後も認証・署名できます。

他の小さな問題を解決するためにinline frame ( <iframe> )あたりが多用されていくかと思います。これは新しい仕組みでもなんでもなく、Google AdsenseのバナーやX(Twitter)のポストを表示したりするのに使われている、他のドメインのHTMLを埋め込むためのものです。これが何故有効かというと、WebAuthnをユーザの認証に使うにあたりサービスが利用するID(Relying Party ID, RP ID)はサービスのホスト名(e.g. app.uniswap.org)を利用する決まりになっており、サービスをまたいで(e.g.someapp.com anotherapp.com 間で)同じ鍵、ひいては同じウォレットの認証をすることに支障が出てしまうためです。そこで、iframeによるウォレットの仕組みを提供しているドメインのHTMLを埋め込むことで、サービス間で同じウォレットを利用することができるでしょう。 勿論、逆にあるサービスは別のコントラクトウォレット実装を使う必要があることを理由として、iframeを使わず自分たちのドメインによるWebAuthn認証を好むかもしれません。テクニカルな知識を持たないユーザにどう危ないサイトを警告するのか、危ないサイトが作られることを防止するのか(例としては、ウォレット提供側はサービスのドメインをホワイトリスト制にしたり)というセキュリティ上の課題はあるものの、便利なUXを提供する手段が増えたのは単純に良いことかと思います。

まだ情報がかなり少ないですが、Portoなどはこの記事に挙げた仕組みの多くを活用していくような記述が見られます。


このように、他のいくつかのEIP, RIPやPasskeyなどのWebの先進技術と組み合わせることで、EIP-7702は非常に多くのユーザに対しウォレットUXの改善をもたらし得ると感じました。コストの関係でまずはL2での利用が目立つかも知れませんが、L1も追いついていくでしょう。楽しみですね!

Subscribe to 0xtomo
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.