EP 3: Walrus และ Seal เข้ารหัสข้อมูล สำหรับเนื้อหาสุดพิเศษ
ปูพื้นฐานระบบจัดการข้อมูลลับบน Sui ด้วย Seal และ Walrus

สวัสดีครับ หายไปกันไปนาน 2-3 สัปดาห์ สาเหตุนั้นมีเพียงหนึ่งเดียวนั้นก็คือ งานเยอะจ้า ไม่รู้จะเยอะไปไหน ไม่ไหวจะเคลีย บทความเลยดองไว้สะนานเลย วันนี้กลับมาต่อกันละนะ ไม่แน่ใจว่าลืมกันไปแล้วยังกับ 2 EP ก่อนหน้านั้น
ไปทบทวนกันก่อนนะ สำหรับ EP นี้เราจะไปต่อกันที่การนำ Seal มาใช้ในการเข้าหรัสข้อมูลของเรานั้นเอง ซึ่งอย่างที่รู้กันว่า Blockchain ทุกคนสามารถเข้าถึงและตรวจสอบได้ แต่กลายเป็นปัญหาใหญ่สำหรับแอปพลิเคชันที่ต้องจัดการข้อมูลที่ละเอียดอ่อน เช่น ข้อความส่วนตัว, ข้อมูลที่เป็นกรรมสิทธิ์, หรือ คอนเทนต์ลับ ของเรา! ถ้าทุกคนเห็นได้หมด ก็ไม่ Exclusive อะดิ
นี่แหละคือที่มาของ Seal ที่เราสามารถสร้างความเป็นส่วนตัว (Privacy) และการควบคุมการเข้าถึง (Access Control) บน Sui network ได้
Seal คืออะไร?
Seal คือ Decentralized Secrets Management (DSM) ที่ช่วยให้นักพัฒนาจัดการข้อมูลลับ (Secrets) ที่ถูกเข้ารหัสไว้ได้อย่างปลอดภัย โดยใช้ Key Servers บนเครือข่าย Sui Network เพื่อกำหนดและบังคับใช้นโยบายการเข้าถึงข้อมูลลับแบบ Trust-Minimized
Seal ออกแบบมาเพื่อให้:
ได้ Privacy แบบเดิม: เหมือนระบบเข้ารหัสข้อมูลทั่วไป
ได้ Security แบบ Web3: ไม่มี single point of failure, ตรวจสอบได้, trust-minimized
สร้าง dApps ที่ยังคงความ Private ได้ บนระบบ Decentralized เต็มรูปแบบ
พูดง่าย ๆ คือ Seal = ความลับ + Decentralized + ควบคุมสิทธิ์ด้วย Smart Contract
ซึ่งด้วยความสามารถของ Seal นักพัฒนาก็จะสามารถสร้าง dApps ที่ยังมีความเป็นส่วนตัวของผู้ใช้ได้โดยไม่ต้องทิ้งความเป็น Decentralized ไปนั้นเอง

ทำไมต้องใช้ Seal + Walrus คู่กัน?
| ระบบ | หน้าที่ |
| Seal | เข้ารหัสข้อมูลลับ + บังคับนโยบายผู้เข้าถึง |
| Walrus | เก็บ payload ที่เข้ารหัสแบบ decentralized |
พอละไปลุยกันเลยดีกว่า ไปเขียนโค๊ดกันเถอะ
เริ่มต้นใช้งาน Seal SDK
ติดตั้ง Seal SDK
ต้องติดตั้ง Seal SDK ก่อนเริ่มใช้งานนะ
npm install @mysten/sealจากนั้นแก้ไขไฟล์
index.tsของเราเพื่อเพิ่มSealClientและตั้งค่าPublic Key ServersสำหรับTestnetนอกจากนี้เราจะสร้างkeypairเพิ่มอีกหนึ่งคู่สำหรับจำลองเป็น "ผู้รับ" คอนเทนต์ของเรา:// index.ts (เพิ่มโค้ดส่วนนี้) import { SealClient, SessionKey, EncryptedObject } from "@mysten/seal"; import { Transaction } from "@mysten/sui/transactions"; import { fromHex } from "@mysten/sui/utils"; // Public key server object IDs สำหรับ Sui Testnet (นี่คือ Key Servers ที่จะช่วยจัดการกุญแจ) const KEY_SERVER_LIST_TESTNET = [ "0x73d05d62c18d9374e3ea529e8e0ed6161da1a141a94d3f76ae3fe4e99356db75", "0xf5d14a81a982144ae441cd7d64b09027f116a468bd36e7eca494f750591623c8", ]; // NOTE: แทนที่ด้วย Package ID ของ Smart Contract Move ที่เราจะ deploy ในอนาคต // ตอนนี้อาจจะยังไม่มี ก็ใช้ '0x...' ไปก่อนได้ const PACKAGE_ID = "0x..."; // ... โค้ดส่วน main() async function main() { // สร้าง SealClient ของเรา const sealClient = new SealClient({ suiClient: suiClient, serverConfigs: KEY_SERVER_LIST_TESTNET.map((id) => ({ objectId: id, weight: 1, })), verifyKeyServers: true, // ตรวจสอบความถูกต้องของ Key Servers }); }สร้าง ฟังก์ชัน ในการเข้ารหัสข้อมูล
async function sendSecretMessage(params: { secret: string; recipient: string; sender: Ed25519Keypair; suiClient: SuiClient; walrusClient: any; sealClient: SealClient }): Promise<string> { const { secret, recipient, sender, suiClient, walrusClient, sealClient } = params; console.log(`\nกำลังเข้ารหัสคอนเทนต์ลับสำหรับ ${recipient}...`); const placeholderPolicyId = "0x" + "0".repeat(64); const { encryptedObject } = await sealClient.encrypt({ threshold: 2, packageId: PACKAGE_ID, id: placeholderPolicyId, data: new TextEncoder().encode(secret), }); console.log("กำลังอัปโหลดข้อมูลที่เข้ารหัสไป Walrus..."); const walrusFile = WalrusFile.from({ contents: encryptedObject }); const writeResult = await walrusClient.walrus.writeFiles({ files: [walrusFile], signer: sender, epochs: 1, deletable: false, }); const blobId = writeResult[0]?.blobId; if (!blobId) throw new Error("Failed to upload encrypted blob to Walrus"); console.log(`Blob ที่เข้ารหัสถูกจัดเก็บแล้ว. Blob ID: ${blobId}`); console.log("กำลังสร้าง SecretMessage Policy Object บนเชน..."); const tx = new Transaction(); tx.moveCall({ target: `${PACKAGE_ID}::message::create_secret_message`, arguments: [tx.pure.address(recipient), tx.pure.string(blobId)], }); const result = await suiClient.signAndExecuteTransaction({ signer: sender, transaction: tx, options: { showObjectChanges: true }, }); const created = result.objectChanges?.find((c) => c.type === "created" && "objectId" in c && c.objectType.includes("secret_message::message::SecretMessage")); if (!created || !("objectId" in created)) { throw new Error("SecretMessage object was not created"); } return created.objectId; }เมื่อต้องการเรียกใช้งานเราสามารถเพิ่ม ฟังก์ชัน ในการใช้งานดังนี้
async function main() { ... ... ... const secret = "My super secret message for you ❤️"; const policyObjectId = await sendSecretMessage({ secret, recipient, sender: keypair, suiClient, walrusClient, sealClient, }); console.log(`✅ SecretMessage policy object id: ${policyObjectId}`); }สำหรับ
recipientนั้นคือ address ของผู้รับนั้นเอง เราสามารถกำหนดได้เลยนะว่าจะส่งไปยัง address ไหน
เรียบร้อบ เราได้ฟังก์ชั่น ในการส่งข้อความเเบบเข้ารหัสไปยังปลายทางแล้วครับ แต่บอกไว้ก่อนเลยตัวอย่างโค๊ดชุดนี้ยังทำงานไม่ได้นะ :P เเน่ละสิ เพราะยังไม่ได้เขียน Move Smart Contract เลยนิ ทำให้เรายังไม่มี Package ID นั้นเอง ถ้านำไปทดสอบและ เรียกใช้งาน มันจะเเสดงข้อความ Error ทันที รอติดตาม EP นะ เราจะไปเขียน Move Smart Contract กัน





