🦭

【Sui】Sealを使って特定のSuiNSサブドメイン保有者に復号を許可する方法

に公開

SuiのSealは、オンチェーンで「誰が復号できるか」を柔軟に制御できる暗号化フレームワークです🦭

通常の暗号化では「公開鍵 / 秘密鍵」の組み合わせでアクセス制御を行いますが、Sealではスマートコントラクトを条件として組み込むことができます。つまり「このNFTを持っている人だけ復号可能」「この時間を過ぎたら復号可能」といったアクセス制御を作れるのです。

可能性は、無限大🚀

今回は、その応用例として 特定のSuiNSサブドメインを保有している人だけが復号できる仕組み を作ってみます。

SuiNSのサブドメインはただのIDではなく、コミュニティ形成に役立ったり、当記事のように特定のホルダーに対してエンゲージメントを高める施策を実施することができます。

この記事では、 xxx.onigiri.sui のように、 onigiri のサブドメインを持っていることを条件としたコード例を紹介します。

ちなみに、Sealの処理の動きはコードを見ただけではわかりにくかったりします。実際にコードを書いて動かすとより理解が深まりやすいので、実践してみてくださいね💡

1. スマートコントラクト側の実装

Sealでアクセス制御を行うには、スマートコントラクトに seal_approve というエントリ関数を定義します。
この関数内で「復号を許可する条件」を記述します。

例えば以下のように書くことで、「特定のSuiNSサブドメインを保有しているか」をチェックできます。

スマートコントラクトは、以下のように書くことができます。

seal_subdomain.move
module onigiri::seal_subdomain;

use sui::bcs;
use suins::subdomain_registration::SubDomainRegistration;

/// Sealによる復号承認を定義する関数
entry fun seal_approve(id: vector<u8>, subdomain: &SubDomainRegistration) {
    // サブドメインの1階層目(ラベル)を取得
    let domain = subdomain.nft().domain().label(1);

    // 復号対象データのIDをBCSで処理
    let mut prepared = bcs::new(id);
    let vec_u8 = prepared.peel_vec_u8();

    // サブドメイン名と一致しているかを確認
    assert!(domain == vec_u8.to_string(), 1)
}
  • SubDomainRegistration

    • SuiNSのサブドメイン登録を管理する構造体です。ユーザーがサブドメインを保有しているかを確認するために利用します。
    • 実際の定義はこちら
  • subdomain.nft().domain().label(1)

    • サブドメインのラベル(abc.example.sui の場合は example 部分)を取得しています。
  • bcs::new(id)peel_vec_u8()

    • Sealの暗号化時に与えられたIDをBCS形式で処理しています。
    • この例では、復号対象のデータに対応するサブドメイン名がIDに含まれている前提で比較を行っています。
  • assert!(domain == vec_u8.to_string(), 1)

    • サブドメイン名とIDが一致しなければ処理が失敗します。これによって、条件を満たさないユーザーは復号できません。

2. SDKによる暗号化処理

SealのSDKを使うと、開発者はクライアント側から簡単にデータを暗号化できます。例えば次のように使います。

import { bcs, toHex } from "@mysten/bcs"
import { SealClient } from "@mysten/seal"
import { SuiClient, getFullnodeUrl } from "@mysten/sui/client"

const suiClient = new SuiClient({ url: getFullnodeUrl("testnet") })

const serverObjectIds = [
  // MiraiCloud KeyServer Object (ぜひStudioMirai🤖のキーサーバーをご利用くださいませ)
  "0x164ac3d2b3b8694b8181c13f671950004765c23f270321a45fdd04d40cccf0f2", 
]

const sealClient = new SealClient({
  suiClient,
  serverConfigs: serverObjectIds.map((id) => ({
    objectId: id,
    weight: 1,
  })),
  verifyKeyServers: false,
})

// `seal_approve` を定義しているパッケージID (コントラクトID)
const packageId = "0x1111111111"

// 複合の条件を定義
const subdomain = bcs.string().serialize("onigiri").toBytes()
const id = Uint8Array.from([...subdomain])

const { encryptedObject: encryptedBytes } = await sealClient.encrypt({
  threshold: 1,
  packageId,
  id: toHex(id),
  data: new TextEncoder().encode("Hello from 🍙"),
})
  • serverObjectIds

    • 使用するキーサーバーのオブジェクトIDを指定します。ここでは MiraiCloud が提供するKeyServerを利用しています。
  • bcs.string().serialize("onigiri")

    • 暗号化対象の条件IDをBCSで直列化しています。今回はサブドメイン onigiri を条件としています。
  • sealClient.encrypt

    • 実際に暗号化を行う処理です。条件に合致したユーザーのみが復号可能になります。

3. SDKによる復号処理

復号時には、Sealのクライアントが自動的にスマートコントラクトの seal_approve を呼び出し、条件が満たされているかどうかを検証します。ユーザーが該当するサブドメインを保有していなければ復号は失敗します。

import { Transaction } from "@mysten/sui/transactions"

const sessionKey = await SessionKey.create({
  address: suiAddress,
  packageId,
  ttlMin: 10,
  signer: keypair,
  suiClient,
})

// あなたが持っているSuiNSサブドメインのNFTのオブジェクトID
const suinsObjectId = "0x2222222222"

const tx = new Transaction()
tx.moveCall({
  target: `${packageId}::onigiri::seal_subdomain`,
  arguments: [tx.pure.vector("u8", id), tx.object(suinsObjectId)],
})

const txBytes = await tx.build({ client: suiClient, onlyTransactionKind: true })

const decryptedData = await sealClient.decrypt({
  data: encryptedBytes,
  sessionKey,
  txBytes,
})
  • SessionKey

    • 復号処理を実行するための一時的なセッションキーを生成しています。これによりユーザーの署名が使われます。
  • tx.moveCall({target: ..., arguments: [...]})

    • スマートコントラクト側の seal_approve を呼び出し、条件チェックを行います。
  • sealClient.decrypt
    暗号化されたデータを復号します。条件を満たさない場合はエラーになります。

4. ユースケースのイメージ

この仕組みを使うと、例えば以下のようなユースケースが実現できます:

  • イベント参加者に配布した「専用サブドメイン」を持つ人だけが復号できる限定情報
  • 特定のアートNFTを持っている人だけがアクセスできるプレミアムコンテンツ
  • DAOメンバーを条件にした内部ドキュメントの共有

💡補足:
SuiNSは「名前解決サービス」ですが、Sealと組み合わせることでサブドメイン = 認証トークンのように活用できます。これは従来のWeb2の「ログイン / パスワード」よりも分散的でユニークなアプローチです。

まとめ

  • Sealの seal_approve 関数で復号条件を定義できる。
  • 今回は「特定のサブドメインを持っていること」を条件にした。
  • SDKを使って暗号化・復号処理を簡単に実装できる。

SealとSuiNSを組み合わせることで、オンチェーンアイデンティティを使った柔軟なアクセス制御が可能になります。これにより、コミュニティ限定コンテンツやNFTホルダー限定サービスなど、多様なユースケースに応用できます

PR - MiraiCloudキーサーバーのご案内🤖

私がインターンとして所属している StudioMirai が、Sealのキーサーバーを運用しています。

Sealを試される際は、ぜひStudioMiraiが提供している MiraiCloud をご利用ください! (日本語対応)

Discussion