Skip to content

ワールド権限とハンドシェイク

「ワールド権限(World Authority)」は、あるワールド・マニフェストが、それが自称するワールドに正当に属しているものであることを、クライアントがどのように検証するかを定義するものです。

VirMesh v1では、ワールドに対して「鍵による権限(Key Authority)」を採用しています。各ワールドは公開鍵によって識別され、その鍵に対して署名の正当性が確認された場合にのみ、ワールド・マニフェストが受理されます。

人間向けには example.com/world 形式の world address を使えます。world address は検索・共有・解決の入口であり、検証済み manifest の worldId に解決してから使います。player handle(例: [email protected])とは別の識別子です。

権限モデル

ワールド識別子(World Identifier)は以下の形式をとります。

text
medi:world:<scheme>:<public key>

初期の scheme(スキーム)は ed25519 です。

text
medi:world:ed25519:base64url-public-key

識別子に含まれる公開鍵は「ワールド・アイデンティティ鍵」です。これは、現在そのワールドをホストしているサーバーとは別の概念であることに注意してください。

最小構成のワールド・マニフェスト

me.virmesh.world.resolveWorld は、署名済みの core manifest と、任意の署名付き world module を返します。core manifest には、不変のワールド・アイデンティティ、現在のホスティング・エンドポイント、および検証後にクライアントが使用可能なプロトコルが記述されています。表示名や instance 作成ポリシーなどの拡張情報は module として返します。

json
{
  "payload": {
    "manifest": {
      "worldId": "medi:world:ed25519:base64url-world-public-key",
      "schema": "obj+me.virmesh.world.manifest",
      "versionId": "2026-04-26T00:00:00Z",
      "endpoint": "https://worlds.example.com/",
      "hostingDelegation": {
        "payload": {
          "worldId": "medi:world:ed25519:base64url-world-public-key",
          "server": "https://worlds.example.com/",
          "capabilities": [
            "resolveManifest",
            "hostLiveSession"
          ],
          "issuedAt": 1770000000
        },
        "signature": "base64-signature-by-world-key"
      },
      "worldProtocols": [
        {
          "name": "me.virmesh.world.websocket",
          "version": "1.0.*"
        }
      ],
      "updated_at": 1770000100
    },
    "modules": {
      "world+me.virmesh.world.profile": {
        "payload": {
          "module": "world+me.virmesh.world.profile",
          "worldId": "medi:world:ed25519:base64url-world-public-key",
          "name": "Example World",
          "description": "A small social world.",
          "tags": ["social", "music"],
          "addresses": ["example.com/world"],
          "updated_at": 1770000200
        },
        "signature": "base64-signature-by-world-key-for-profile-module"
      },
      "world+me.virmesh.world.instancePolicy": {
        "payload": {
          "module": "world+me.virmesh.world.instancePolicy",
          "worldId": "medi:world:ed25519:base64url-world-public-key",
          "createInstance": false,
          "defaultCapacity": 32,
          "maxCapacity": 32,
          "joinPolicies": ["public"],
          "updated_at": 1770000200
        },
        "signature": "base64-signature-by-world-key-for-instance-policy-module"
      }
    }
  },
  "signature": "base64-signature-by-world-key"
}

Manifest の各 worldProtocols 要素は、nameversion によって、その world が対応する live session protocol を宣言します。接続先、ポート、TLS SNI、URI などの instance 固有の値は manifest には含めず、me.virmesh.worldInstance.listInstance または getInstance で返る instance object の worldProtocols[].information から取得します。

トップレベルの signature は、payload.manifest を Canonical JSON(正規化された JSON)化したものに対して署名を行います。検証側は payload.manifest.worldId から公開鍵を導出し、その鍵を用いて core manifest の署名を検証します。

payload.modules.*.signature は、対応する payload.modules.*.payload の Canonical JSON に対する world identity key の署名です。クライアントは module payload 内の worldIdpayload.manifest.worldId と一致する場合だけ、その module を使えます。

モジュールモデル

world module は、core manifest から分離された署名付きの拡張情報です。v1 では、少なくとも次の module を標準として扱います。

Module内容
world+me.virmesh.world.profile表示名、説明文、tag、world address、thumbnail などの表示情報。
world+me.virmesh.world.instancePolicycreateInstance の対応可否、既定 capacity、利用可能な join policy など。

module は個別に署名されます。WorldServer は profile だけを更新したい場合、core manifest 全体ではなく world+me.virmesh.world.profile の payload と署名を更新できます。

json
{
  "payload": {
    "module": "world+me.virmesh.world.profile",
    "worldId": "medi:world:ed25519:base64url-world-public-key",
    "name": "Example World",
    "description": "A small social world.",
    "tags": ["social", "music"],
    "addresses": ["example.com/world"],
    "updated_at": 1770000200
  },
  "signature": "base64-signature-by-world-key-for-profile-module"
}

クライアントのフロー

最もシンプルなクライアントのフローは以下の通りです。

  1. world address(例: example.com/world)または catalog entry、または既知の worldIdme.virmesh.world.resolveWorld で署名付き manifest response に解決する。特定リビジョンを要求する場合は versionId または hash クエリを使う。
  2. payload.manifest.worldId を読み取り、そこからワールド公開鍵を導出する。
  3. payload.manifest の Canonical JSON に対するトップレベルのマニフェスト署名を検証する。
  4. hostingDelegation.payload.worldIdpayload.manifest.worldId と一致することを確認する。
  5. hostingDelegation.payload の Canonical JSON に対する hostingDelegation.signature を検証する。
  6. 委譲(delegation)の内容に、次のステップで必要となる「権限(capability)」が含まれているか確認する。
  7. hostingDelegation.payload.expiresAt が存在する場合は、manifest の endpoint や live session protocol 宣言を解釈する前に期限をチェックする。
  8. payload.modules.*.payload を対応する payload.modules.*.signature で検証し、module 内の worldId が core manifest と一致することを確認する。
  9. リストされたアセットを取得し、信頼できるワールド・コンテンツとして読み込む前に hash を検証する。
  10. manifest の worldProtocols で対応 protocol を確認し、instance 解決後に instance 側の worldProtocols[].information を使ってライブ・セッションを開始する。

いずれかの検証ステップで失敗した場合、クライアントは「署名のないサーバー権限型ワールド」としてそのレスポンスを許容するような、フォールバック(妥協)を行ってはなりません。

ホスティングの委譲(Hosting delegation)

ホスティングの委譲により、不変のワールド鍵を用いて、特定のサーバーにワールドのホストや解決を行う権限を与えることができます。

委譲のペイロードは、ワールド・アイデンティティ鍵、またはワールド・アイデンティティ鍵から権限を委譲されたマニフェスト鍵によって署名されます。v1では、ワールド鍵による直接の署名から運用を開始します。

json
{
  "worldId": "medi:world:ed25519:base64url-world-public-key",
  "server": "https://worlds.example.com/",
  "capabilities": [
    "resolveManifest",
    "hostLiveSession"
  ],
  "issuedAt": 1770000000
}

権限(Capabilities)は完全一致の文字列です。resolveManifest のみが委譲されたサーバーを、ライブ・セッションをホストする権限があるものとして扱うことはできません。

expiresAt は任意です。省略された delegation は、明示的な失効ルールが導入されるまで有効な long-lived delegation として扱います。短命の代理ホスティングやイベント用途では expiresAt を付け、個人運営や静的ホスティングでは省略できます。

署名の対象

マニフェストの署名は、不変のワールド・メタデータと、取得したコンテンツを検証するために必要なデータを対象としています。

フィールド署名が必要な理由
worldIdマニフェストを特定のワールド・アイデンティティに紐付けるため。
schema同じペイロードが別のスキーマとして解釈されるのを防ぐため。
versionIdキャッシュやエクスプローラーに、不変のバージョン・ハンドルを提供するため。
endpointこのバージョンにおいて意図されたリゾルバーまたはホストを明示するため。
hostingDelegationエンドポイントに正当な権限があることをクライアントが検証できるようにするため。
worldProtocols対応 protocol 宣言のダウングレードを防ぐため。instance 固有の接続パラメータは instance object で扱います。
assets[].hashミラーサイトやCDNが、信頼された権限を持たずともコンテンツを配信できるようにするため。

表示名や説明文などの module payload は、core manifest のトップレベル署名ではなく module ごとの署名で検証します。

ライブ状態(動的なデータ)はマニフェスト署名の対象外です。位置情報の更新、音声トラフィック、物理演算の計算、プレゼンス(在室情報)などは、サーバーの正当性が確認された後のライブ・セッションの一部として信頼されます。

運用上の注意

ワールド・アイデンティティ鍵は、長期的な権限を持つものとして扱う必要があります。運用者は、これを頻繁にアクセスされる(漏洩リスクの高い)サーバー上のアクティブな鍵として使用するのは避けるべきです。

本番環境のワールドでは、以下の役割を分離してください。

鍵の種類用途
ワールド・アイデンティティ鍵medi:world:<scheme>:<public key> を定義し、長期的な権限の署名を行う。
マニフェスト鍵(将来的なオプション)マニフェストを頻繁に更新するために委譲される鍵。
サーバー鍵(将来的なオプション)短期間のライブ・セッション認証に使用される運用鍵。

もしワールド・アイデンティティ鍵が漏洩した場合、攻撃者はそのワールドIDに対して有効なマニフェストを作成できてしまいます。鍵のローテーションや失効(tombstone)ルールはまだv1には含まれていません。これを「復旧可能」なものとして扱う前に、侵害されたアカウントと将来の鍵移行に関するドラフト・ノートを確認してください。

サーバー権限型ワールド(Server-authoritative worlds)

サーバー権限型ワールドは、v1の権限モデルには含まれません。これらはローカル開発、一時的なイベント、あるいは軽量な個人サーバーには有用かもしれませんが、異なる信頼ルールが適用されます。

現在のドラフトは Server Authority Worlds で管理されています。

次のステップ

  • Canonical JSONと署名のルールについては、Transport を参照してください。
  • プレイヤーの公開鍵アイデンティティについては、Identity を参照してください。
  • 未解決のサーバー権限オプションについては、Server Authority Worlds を参照してください。