# EP 3: Walrus และ Seal เข้ารหัสข้อมูล สำหรับเนื้อหาสุดพิเศษ

สวัสดีครับ หายไปกันไปนาน 2-3 สัปดาห์ สาเหตุนั้นมีเพียงหนึ่งเดียวนั้นก็คือ งานเยอะจ้า ไม่รู้จะเยอะไปไหน ไม่ไหวจะเคลีย บทความเลยดองไว้สะนานเลย วันนี้กลับมาต่อกันละนะ ไม่แน่ใจว่าลืมกันไปแล้วยังกับ 2 EP ก่อนหน้านั้น

* [https://onthemove.contributiondao.com/ep-1-walrus-and-seal](https://onthemove.contributiondao.com/ep-1-walrus-and-seal)
    
* [https://onthemove.contributiondao.com/ep-2-walrus-programmable-storage](https://onthemove.contributiondao.com/ep-2-walrus-programmable-storage)
    

ไปทบทวนกันก่อนนะ สำหรับ 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 SDK](https://cdn.hashnode.com/res/hashnode/image/upload/v1763225126468/a180e825-017d-45ba-83cb-a76d0520e373.png align="center")

**ทำไมต้องใช้ Seal + Walrus คู่กัน?**

| ระบบ | หน้าที่ |
| --- | --- |
| **Seal** | เข้ารหัสข้อมูลลับ + บังคับนโยบายผู้เข้าถึง |
| **Walrus** | เก็บ payload ที่เข้ารหัสแบบ decentralized |

พอละไปลุยกันเลยดีกว่า ไปเขียนโค๊ดกันเถอะ

**เริ่มต้นใช้งาน Seal SDK**

1. ติดตั้ง Seal SDK
    
    ต้องติดตั้ง Seal SDK ก่อนเริ่มใช้งานนะ
    
    ```bash
    npm install @mysten/seal
    ```
    
2. จากนั้นแก้ไขไฟล์ `index.ts` ของเราเพื่อเพิ่ม `SealClient` และตั้งค่า `Public Key Servers` สำหรับ `Testnet` นอกจากนี้เราจะสร้าง `keypair` เพิ่มอีกหนึ่งคู่สำหรับจำลองเป็น "ผู้รับ" คอนเทนต์ของเรา:
    
    ```typescript
    // 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
      });
    }
    ```
    
3. สร้าง ฟังก์ชัน ในการเข้ารหัสข้อมูล
    
    ```typescript
    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;
    }
    ```
    
4. เมื่อต้องการเรียกใช้งานเราสามารถเพิ่ม ฟังก์ชัน ในการใช้งานดังนี้
    
    ```typescript
    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 กัน
