メインコンテンツまでスキップ

2.1 zkLogin関連技術解説 ⚡️

SuiのzkLoginは、GoogleやFacebookなどの既存のWebアカウント情報を使って、ブロックチェーン上のウォレット(Suiアドレス)を生成し、dApps(分散型アプリケーション)を利用可能にする画期的な機能です。

この仕組みにより、ユーザーは従来のウォレット管理で必須だったシードフレーズや秘密鍵を覚える必要がなくなり、web3への参加ハードルが劇的に下がります。

このレッスンでは、zkLoginを支える主要な技術要素と、実際に認証が行われるまでの流れを初心者にも分かりやすく解説します。

主要機能

このプロジェクトで実装するアプリの主要機能です。

  • zkLogin認証機能
  • Google OAuth による OpenID 認証機能
  • Supabase連携によるユーザーソルトの保管機能
  • JWTとユーザーソルトを元にしたSuiウォレット導出機能
  • 1 SUIの送金デモ機能
  • NFTのミントデモ機能

zkLoginを支える技術要素

zkLoginは、複数の技術要素を組み合わせることで、安全で使いやすい体験を実現しています。

1. OpenID Connect(OIDC)とJSON Web Token(JWT)

  • OIDCは、Googleなどのプロバイダーがユーザー認証に使用する標準的なプロトコルです。
  • ユーザーがOIDCプロバイダー(OP)にログインし、認証に成功すると、署名付きのJWT(JSON Web Token) を取得します。
  • JWTは、ヘッダーペイロード署名の3つの部分で構成され、ユーザーに関する情報をJSON形式で含みます。zkLoginは、このJWTを「ユーザーが本人であること」の証明の基盤として利用します。

2. 一時的なキーペア(Ephemeral Key Pair)

  • ユーザーはJWTを取得する前に、そのセッション中だけ一時的に利用する秘密鍵と公開鍵のペア(eph_sk, eph_pk)を生成します。
  • この一時的な公開鍵(eph_pk)は、OIDCプロトコルにおける nonceパラメータに埋め込まれます。
    nonceはリプレイ攻撃(一度使用されたデータを再利用する攻撃)を防ぐための使い捨ての値です。
  • このキーペアはセッションが終了すると破棄されるため、ユーザーが管理する必要はありません。
    本デモアプリではブラウザのローカルストレージに保存しますが、本番環境ではより安全な方法が推奨されます。

3. ユーザーソルト(User Salt)

  • JWTには、ユーザーを識別するためのsub(subject)IDが含まれています。

    しかし、これを直接使用すると、SNSアカウントとウォレットが紐づいてしまい、プライバシー上のリスクが生まれます。

  • そこでzkLoginでは、salt(ソルト) と呼ばれるランダムな値をユーザーの識別子と組み合わせて、Suiアドレスを生成します。

  • saltがあることで、第三者はユーザーのSuiアドレスから元のSNSアカウントを特定することができなくなり、プライバシーが保護されます。

4. ゼロ知識証明 (Zero-Knowledge Proof, ZKP)

  • ZKPは、「ある情報を知っている」という事実を、その情報自体を相手に明かすことなく証明するための技術です。
  • zkLoginでは、ZKPを利用して以下の2点を証明します。
    1. ユーザーが、特定のOIDCプロバイダー(Googleなど)が発行した有効なJWTを所有していること。
    2. そのJWTのnonceに、一時的な公開鍵(eph_pk)が含まれていること。
  • これにより、JWTに含まれるメールアドレスなどの個人情報をブロックチェーン上に公開することなく、本人確認を完結させることができます。

5. ZK証明サービス (ZK Proving Service)

  • ZKPの生成はバックエンド側で実施します。Dockerコンテナを建てることも可能ですが、今回はzkLoginでは証明の生成を専門のバックエンドサーバー(Mysten Labsが運営するProver)にオフロードします。
  • ユーザーのdAppは、必要な情報をこのサービスに送信し、ZKPを返してもらうことで、ユーザーのデバイスに負荷をかけることなく証明を生成できます。

zkLogin 認証の8ステップ

実際にユーザーがdAppにログインしてからトランザクションを送信するまでの流れを、8つのステップで見ていきましょう。

  1. 一時的な鍵ペア生成

    • dAppがユーザーのために一時的な秘密鍵(eph_sk)と公開鍵(eph_pk)を生成します。
    • 有効期限(max_epoch)と公開鍵を組み合わせてnonceも生成します。
  2. JWT取得

    • ユーザーをGoogleなどのOAuthプロバイダーのログイン画面にリダイレクトします。
    • ログインが成功すると、プロバイダーはnonceを含んだJWTをdAppに返します。
  3. JWTデコード

    • dAppは受け取ったJWTをデコードして、headerpayloadの情報を読み取ります。
  4. ユーザーソルト取得

    • dAppは、ユーザーごとに一意のsaltを取得します。
    • 本プロジェクトでは、このsaltをSupabaseのデータベースに保存・管理します。初めてのユーザーの場合は新しいsaltを生成して保存します。
  5. Suiアドレス生成

    • JWTに含まれるiss(プロバイダー情報)、aud(アプリ情報)、sub(ユーザーID)と、ステップ4で取得したsaltを組み合わせて、ユーザー固有のSuiアドレスを計算します。
    • この仕組みにより、同じGoogleアカウントでも、利用するdAppが異なれば別々のSuiアドレスが生成されるため、プライバシーが保たれます。
  6. ZK証明取得 (Proving)

    • dAppは、JWTや関連情報をMysten LabsのZK証明サービス(Prover)に送信し、ゼロ知識証明(ZKP)を要求します。
    • Proverは証明を生成し、dAppに返します。一度生成された証明は、一時鍵の有効期限が切れるまで再利用できます。
  7. zkLogin署名生成

    • dAppは、Proverから受け取ったZKPと、ユーザーが実行したいトランザクションのデータを結合します。
    • これを最初(ステップ1)に生成した一時的な秘密鍵(eph_sk)で署名し、最終的なzkLogin署名を生成します。
  8. トランザクション送信

    • dAppは、生成されたzkLogin署名を使ってSuiネットワークにトランザクションを送信します。
    • Suiのフルノードは署名を検証し、問題がなければトランザクションを実行します。

🙋‍♂️ 質問する

技術的な疑問はDiscord #zkで質問してください。