- TẤT CẢ BLOB TRÊN WALRUS ĐỀU PUBLIC - có thể bị khám phá bởi tất cả mọi người
- Walrus chỉ đảm bảo availability (tính sẵn có) và integrity (toàn vẹn) của dữ liệu
- BẮT BUỘC phải mã hóa bằng Seal nếu lưu trữ dữ liệu bí mật/riêng tư
- Walrus sử dụng erasure coding để phân mảnh và phân tán dữ liệu
- IBE (Identity-Based Encryption) với threshold cryptography
- Không bên nào giữ toàn bộ khóa giải mã - key servers phân tán giữ key shares
- Access control onchain - mọi giải mã phải qua Move function
seal_approve - Tích hợp tự nhiên với Walrus - encrypted data trên Walrus, access policy onchain
- Identity =
[packageId][inner_id] packageId: namespace cho access controlinner_id: ID cụ thể (ví dụ: lora_id, timestamp cho time-lock)
┌──────────────────────────────────────────────────────────────────┐
│ FRONTEND (Next.js) │
│ - Sui Wallet integration │
│ - Seal SDK (@mysten/seal) │
│ - SessionKey management │
└────────┬──────────────────────────────────────┬──────────────────┘
│ │
┌────▼─────────┐ ┌────▼───────────┐
│ SUI CHAIN │ │ WALRUS STORAGE │
│ │ │ │
│ Move Smart │◄────────────────────►│ Encrypted │
│ Contracts: │ Verify onchain │ Blobs │
│ │ │ │
│ - seal_ │ │ (Public but │
│ approve() │ │ encrypted) │
│ - LoRA │ │ │
│ Asset │ │ │
│ - Rental │ │ │
│ System │ │ │
└──────┬───────┘ └────────────────┘
│ ▲
│ Verify License │
│ │ Fetch blob
┌──────▼────────┐ ┌──────────────────┘
│ SEAL KEY │ │
│ SERVERS │◄────────┤
│ (Threshold │ Request│
│ 2/3 quorum) │ key │
└───────────────┘ share │
│ │
│ Return key share │
│ │
┌──────▼──────────────────▼──────┐
│ AI BACKEND │
│ - Seal SDK │
│ - SessionKey │
│ - ComfyUI/Stable Diffusion │
│ - Inference Engine │
└─────────────────────────────────┘
Mục đích: Deploy Move contract với seal_approve function
Công việc:
-
Viết Move module với
seal_approvefunction- Function signature:
entry fun seal_approve(id: vector<u8>, ...other_params) id: inner identity (không bao gồm packageId, Seal sẽ tự thêm)- Function phải side-effect free (không modify state trong logic approve)
- Return void, nhưng
assert!()nếu không cho phép
- Function signature:
-
Example seal_approve cho rental:
entry fun seal_approve( id: vector<u8>, // inner identity = bcs::to_bytes(lora_id) license: &RentalLicense, // reference to license object clock: &Clock // Sui Clock object ) { // Parse inner id to get lora_id let mut bcs_id = bcs::new(id); let lora_id_from_id = bcs_id.peel_address(); // Verify license matches lora assert!(license.lora_id == lora_id_from_id, EInvalidLoRA); // Verify license not expired assert!(license.end_time > clock.timestamp_ms(), EExpiredLicense); // Verify license active assert!(license.is_active == true, EInactiveLicense); }
-
Deploy contract lên Sui:
sui client publish- Lưu lại
packageId
-
Tạo LoRAAsset object:
public fun create_lora( name: String, description: String, ctx: &mut TxContext ): LoRAAsset { LoRAAsset { id: object::new(ctx), name, description, owner: tx_context::sender(ctx), walrus_blob_id: option::none(), // Sẽ update sau is_active: true } }
Mục đích: Encrypt LoRA file trước khi upload
Công việc:
-
Setup SealClient:
import { SealClient, getAllowlistedKeyServers } from '@mysten/seal'; import { SuiClient, getFullnodeUrl } from '@mysten/sui.js/client'; const suiClient = new SuiClient({ url: getFullnodeUrl('testnet') }); // Get verified key servers cho testnet const serverObjectIds = getAllowlistedKeyServers('testnet'); const sealClient = new SealClient({ suiClient, serverConfigs: serverObjectIds.map(id => ({ objectId: id, weight: 1, // Equal weight cho mỗi server })), verifyKeyServers: false, // Set true cho production });
-
Read file và encrypt:
// Read LoRA file const fileBuffer = await file.arrayBuffer(); const fileBytes = new Uint8Array(fileBuffer); // Prepare inner identity = lora_id const loraIdBytes = fromHEX(loraAsset.id); // Convert lora ID to bytes // Encrypt const { encryptedObject, key } = await sealClient.encrypt({ threshold: 2, // Cần 2/3 key servers để decrypt packageId: PACKAGE_ID, // Package ID từ step 1.3 id: loraIdBytes, // Inner identity = lora_id data: fileBytes, // LoRA file content }); // Optional: Backup symmetric key an toàn // key có thể dùng để decrypt thủ công nếu cần securelyStoreKey(loraAsset.id, key);
-
Parse encrypted object (optional, để debug):
import { EncryptedObject } from '@mysten/seal'; const parsed = EncryptedObject.parse(encryptedObject); console.log('Encrypted with ID:', parsed.id);
Mục đích: Store encrypted data lên Walrus
Công việc:
-
Upload qua Walrus CLI:
# Save encryptedObject to file first (in your upload handler) echo "<encryptedObject_hex>" | xxd -r -p > lora_encrypted.bin # Upload to Walrus walrus store lora_encrypted.bin --epochs 100 # Output: blob_id
-
Hoặc upload qua HTTP API:
const response = await fetch('https://publisher.walrus-testnet.walrus.space/v1/store', { method: 'PUT', headers: { 'Content-Type': 'application/octet-stream', }, body: encryptedObject, }); const result = await response.json(); const blobId = result.newlyCreated.blobObject.blobId;
-
Update LoRAAsset trên Sui:
const tx = new Transaction(); tx.moveCall({ target: `${PACKAGE_ID}::lora_asset::update_blob_id`, arguments: [ tx.object(loraAssetId), tx.pure.string(blobId), ], }); await signAndExecute(tx);
-
Tạo RentalPolicy:
const tx = new Transaction(); tx.moveCall({ target: `${PACKAGE_ID}::rental_system::create_rental_policy`, arguments: [ tx.object(loraAssetId), tx.pure.u64(pricePerDay), tx.pure.u64(minDuration), tx.pure.u64(maxDuration), ], }); await signAndExecute(tx);
- ✅ LoRA được mã hóa bằng Seal (threshold encryption)
- ✅ Encrypted blob lưu trên Walrus (public nhưng không decrypt được)
- ✅ LoRAAsset onchain chứa blob_id
- ✅ RentalPolicy ready cho thuê
Công việc:
- Query LoRAAsset objects từ Sui
- Hiển thị danh sách với metadata
- User chọn LoRA và click "Rent"
Công việc:
-
Tạo transaction thuê:
const tx = new Transaction(); // Transfer payment const [coin] = tx.splitCoins(tx.gas, [pricePerDay * duration]); // Call rent function tx.moveCall({ target: `${PACKAGE_ID}::rental_system::rent_lora`, arguments: [ tx.object(MARKETPLACE_ID), tx.object(loraId), tx.pure.u64(duration), coin, ], }); await wallet.signAndExecuteTransaction({ transaction: tx });
-
Smart contract tạo RentalLicense:
public fun rent_lora( marketplace: &mut RentalMarketplace, lora_id: ID, duration: u64, payment: Coin<SUI>, clock: &Clock, ctx: &mut TxContext ) { // Verify payment let policy = get_rental_policy(marketplace, lora_id); assert!(coin::value(&payment) >= policy.price_per_day * duration, EInsufficientPayment); // Create license let license = RentalLicense { id: object::new(ctx), lora_id, renter: tx_context::sender(ctx), start_time: clock.timestamp_ms(), end_time: clock.timestamp_ms() + (duration * 86400000), // days to ms is_active: true, usage_count: 0, }; // Transfer license to renter transfer::transfer(license, tx_context::sender(ctx)); // Process payment process_payment(marketplace, payment); // Emit event event::emit(LoRARented { lora_id, renter: tx_context::sender(ctx), duration }); }
- ✅ RentalLicense NFT trong wallet của renter
- ✅ License recorded onchain với end_time
- ✅ Payment processed
Công việc:
- User chọn LoRA đã thuê
- Nhập prompt
- Gửi request tới Backend với wallet signature
Công việc:
def verify_license(user_address, lora_id):
# Query Sui cho license
licenses = sui_client.get_owned_objects(
user_address,
filter={"StructType": f"{PACKAGE_ID}::rental_system::RentalLicense"}
)
# Find license for this LoRA
for license in licenses:
if license.lora_id == lora_id and license.is_active:
if license.end_time > current_timestamp_ms():
return license
raise Unauthorized("No valid license found")Mục đích: SessionKey cần cho decrypt
Công việc:
import { SessionKey } from '@mysten/seal';
// Create SessionKey
const sessionKey = await SessionKey.create({
address: userAddress, // Renter's address
packageId: PACKAGE_ID,
ttlMin: 60, // Session valid for 60 minutes
suiClient,
});
// Get personal message to sign
const personalMessage = sessionKey.getPersonalMessage();
// User signs message (in practice, cached or signed earlier)
// For backend: có thể dùng Signer directly
const signer = await getBackendSigner();
await sessionKey.setPersonalMessageSignature(
await signer.signPersonalMessage(personalMessage)
);
// sessionKey is now initializedLưu ý về SessionKey:
- SessionKey cần user signature để initialize
- TTL (time-to-live) giới hạn thời gian sử dụng
- Có thể cache trong IndexedDB (frontend) hoặc memory (backend)
- Optional: có thể pass
mvr_name(Move Package Registry name) để improve UX
Mục đích: Tạo proof onchain để Seal verify
Công việc:
const tx = new Transaction();
// Prepare inner identity = lora_id
const loraIdBytes = fromHEX(loraId);
tx.moveCall({
target: `${PACKAGE_ID}::seal_integration::seal_approve`,
arguments: [
tx.pure.vector("u8", loraIdBytes), // inner id
tx.object(licenseId), // license object
tx.object('0x6'), // Clock object (always 0x6)
],
});
// Build transaction (ONLY transactionKind, không cần sign)
const txBytes = await tx.build({
client: suiClient,
onlyTransactionKind: true, // ⭐ QUAN TRỌNG
});
// txBytes này sẽ dùng cho decryptLưu ý quan trọng:
- KHÔNG execute transaction này
- Chỉ cần
txBytes(transactionKind) - Seal SDK sẽ dùng txBytes để verify onchain
- Transaction phải valid (seal_approve không throw error)
Công việc:
import requests
# Get blob_id from LoRAAsset
lora_asset = sui_client.get_object(lora_id)
blob_id = lora_asset.data.walrus_blob_id
# Fetch from Walrus aggregator
response = requests.get(f'https://aggregator.walrus-testnet.walrus.space/v1/{blob_id}')
if response.status_code == 200:
encrypted_bytes = response.content
else:
raise Exception(f'Failed to fetch blob: {response.status_code}')Mục đích: Giải mã để lấy LoRA weights
Công việc:
// Decrypt
const decryptedBytes = await sealClient.decrypt({
data: encryptedBytes, // From Walrus
sessionKey: sessionKey, // Initialized SessionKey
txBytes: txBytes, // Transaction kind from step 4
});
// decryptedBytes is now the original LoRA .safetensors fileSeal thực hiện internally:
- Verify
txBytesonchain (simulate transaction) - Nếu seal_approve pass → request key shares từ key servers
- Key servers verify:
- Transaction valid?
- Signature match?
- Policy allow?
- Each key server return key share
- Tổng hợp key shares (threshold: 2/3)
- Decrypt data với reconstructed key
- Return plaintext
Lưu ý:
- Nếu seal_approve fail → decrypt fail
- Nếu không đủ key servers respond → decrypt fail
- Key servers có rate limiting → design app carefully
- Cache keys internally trong SealClient (reuse client instance)
Công việc:
import safetensors
# Load LoRA vào memory (không save file)
lora_tensors = safetensors.torch.load(io.BytesIO(decrypted_bytes))
# Load vào ComfyUI/Stable Diffusion
model.load_lora(lora_tensors)
# Run inference
image = model.generate(prompt, settings)
# Apply watermark
watermarked_image = apply_watermark(image, license_id)
# Cleanup
del lora_tensors
del decrypted_bytes
return watermarked_imageCông việc:
const tx = new Transaction();
tx.moveCall({
target: `${PACKAGE_ID}::rental_system::increment_usage`,
arguments: [
tx.object(licenseId),
],
});
await signAndExecute(tx);- ✅ Image generated với LoRA
- ✅ LoRA weights không leak (memory-only)
- ✅ Usage tracked onchain
- ✅ Audit trail immutable
Công việc:
// Cronjob chạy định kỳ
async function revokeExpiredLicenses() {
// Query all active licenses
const licenses = await sui_client.queryEvents({
query: { MoveEventType: `${PACKAGE_ID}::rental_system::LoRARented` }
});
for (const license of licenses) {
if (license.end_time < Date.now()) {
// Revoke
const tx = new Transaction();
tx.moveCall({
target: `${PACKAGE_ID}::rental_system::revoke_license`,
arguments: [tx.object(license.id)],
});
await signAndExecute(tx);
}
}
}Cơ chế:
- Lần inference tiếp theo, seal_approve sẽ check:
assert!(license.end_time > clock.timestamp_ms(), EExpiredLicense);
- Nếu expired → assert fail → transaction fail → decrypt fail
- Backend return error: "License expired"
- ✅ Auto-enforcement qua seal_approve
- ✅ Không cần manual revocation (nhưng nên có cho consistency)
- ✅ Onchain audit trail
struct LoRAAsset has key, store {
id: UID,
name: String,
description: String,
owner: address,
walrus_blob_id: Option<String>,
is_active: bool,
}
public fun create_lora(...): LoRAAsset { ... }
public fun update_blob_id(asset: &mut LoRAAsset, blob_id: String) { ... }
public fun deactivate(asset: &mut LoRAAsset) { ... }struct RentalPolicy has key, store {
id: UID,
lora_id: ID,
price_per_day: u64,
min_duration: u64,
max_duration: u64,
}
struct RentalLicense has key, store {
id: UID,
lora_id: ID,
renter: address,
start_time: u64,
end_time: u64,
is_active: bool,
usage_count: u64,
}
public fun create_rental_policy(...) { ... }
public fun rent_lora(...): RentalLicense { ... }
public fun revoke_license(license: &mut RentalLicense) { ... }
public fun increment_usage(license: &mut RentalLicense) { ... }const EInvalidLoRA: u64 = 1;
const EExpiredLicense: u64 = 2;
const EInactiveLicense: u64 = 3;
/// Seal approval function
/// Identity structure: [packageId][inner_id]
/// inner_id = bcs::to_bytes(lora_id)
entry fun seal_approve(
id: vector<u8>, // Inner identity only
license: &RentalLicense, // Reference to license
clock: &Clock // Sui Clock (0x6)
) {
// Parse inner id to get lora_id
let mut bcs_id = bcs::new(id);
let lora_id_from_id = bcs_id.peel_address();
let remaining = bcs_id.into_remainder_bytes();
// Verify entire id consumed
assert!(remaining.length() == 0, EInvalidLoRA);
// Verify license matches LoRA
assert!(license.lora_id == lora_id_from_id, EInvalidLoRA);
// Verify license not expired
assert!(license.end_time > clock.timestamp_ms(), EExpiredLicense);
// Verify license active
assert!(license.is_active, EInactiveLicense);
// If all checks pass, function returns normally
// If any check fails, assert! will abort transaction
}Lưu ý về seal_approve:
- Function phải là
entry fun - Phải side-effect free (không modify state trong approval logic)
- Có thể read objects qua reference (
&Object) - Dùng
assert!()để reject access - Seal sẽ simulate transaction để verify
class SealClient {
constructor(config: {
suiClient: SuiClient;
serverConfigs: Array<{
objectId: string; // Key server object ID
weight: number; // Weight for selection
apiKeyName?: string; // For authenticated servers
apiKey?: string;
}>;
verifyKeyServers?: boolean; // Verify URLs against onchain data
});
// Encrypt data
async encrypt(options: {
threshold: number; // Min key servers needed (e.g., 2 for 2/3)
packageId: string; // Package containing seal_approve
id: Uint8Array; // Inner identity (not including packageId)
data: Uint8Array; // Data to encrypt
}): Promise<{
encryptedObject: Uint8Array;
key: Uint8Array; // Symmetric key (for backup)
}>;
// Decrypt data
async decrypt(options: {
data: Uint8Array; // Encrypted data
sessionKey: SessionKey; // Initialized SessionKey
txBytes: Uint8Array; // Transaction bytes (onlyTransactionKind)
}): Promise<Uint8Array>;
// Fetch multiple keys efficiently
async fetchKeys(options: {
ids: string[]; // Multiple identity IDs
txBytes: Uint8Array; // Transaction with multiple seal_approve calls
sessionKey: SessionKey;
threshold: number;
}): Promise<Map<string, Key>>;
}class SessionKey {
// Create new session key
static async create(options: {
address: string; // Sui address
packageId: string; // Package ID
ttlMin: number; // Time-to-live in minutes
suiClient: SuiClient;
mvr_name?: string; // Optional: package name for better UX
}): Promise<SessionKey>;
// Get message to sign
getPersonalMessage(): Uint8Array;
// Initialize with signature
setPersonalMessageSignature(signature: Signature): void;
// Persistence
static async import(data: Uint8Array): Promise<SessionKey>;
export(): Uint8Array;
}// Get allowlisted key servers
function getAllowlistedKeyServers(network: 'testnet' | 'mainnet'): string[];
// Parse encrypted object
class EncryptedObject {
static parse(bytes: Uint8Array): {
id: string;
// ... other metadata
};
}Open Mode:
- Shared master key cho tất cả clients
- Public access, không cần authentication
- Dùng cho development/testing
- Rate limiting theo source IP
Permissioned Mode:
- Mỗi client có dedicated master key
- Cần API key authentication
- Dùng cho production
- Custom rate limits per client
Mysten Labs (Open):
- mysten-testnet-1:
https://seal-key-server-testnet-1.mystenlabs.com - mysten-testnet-2:
https://seal-key-server-testnet-2.mystenlabs.com
Ruby Nodes:
- Open:
https://free-eu-central-1.api.rubynodes.io- Object ID:
0x781389fae54633649d78b731b708c5b363cf7fa4753a48997d4f6f82d5cc5b98
- Object ID:
- Permissioned:
https://starter-eu-central-1.api.rubynodes.io
NodeInfra:
- Open:
https://open-seal-testnet.nodeinfra.com- Object ID:
0x5466b7df5c15b508678d51496ada8afab0d6f70a01c10613123382b1b8131007
- Object ID:
- Permissioned:
https://seal-testnet.nodeinfra.com
Recommendation:
- Development: Dùng Open mode với 3 key servers, threshold = 2
- Production: Setup Permissioned mode với providers, threshold = 2/3
# Store file
walrus store <file_path> --epochs <number>
# Output
Stored blob with ID: <blob_id>curl -X PUT \
https://publisher.walrus-testnet.walrus.space/v1/store \
-H "Content-Type: application/octet-stream" \
--data-binary @<file_path>Response:
{
"newlyCreated": {
"blobObject": {
"id": "0x...",
"blobId": "<blob_id>",
"size": 123456,
...
}
}
}curl https://aggregator.walrus-testnet.walrus.space/v1/<blob_id>- Recommended: threshold = 2, total servers = 3 (2/3 quorum)
- Cao hơn → more secure nhưng higher latency
- Thấp hơn → faster nhưng less resilient
- TTL không quá dài (60 minutes recommended)
- Rotate sessions định kỳ
- Store securely (IndexedDB frontend, memory backend)
- Clear sau khi dùng xong
- CRITICAL: Validate ALL inputs
- Check timestamp để prevent old transactions
- Side-effect free (không modify state)
- Test edge cases thoroughly
- Verify wallet signatures
- Rate limiting per user
- Memory-only LoRA loading
- Clear sensitive data sau inference
- Monitor suspicious patterns
- Symmetric key từ encrypt() có thể backup
- Encrypt backup key với user's master key
- Store trong secure storage
- Có recovery flow nếu key servers down
Rủi ro: Không đủ key servers respond Giảm thiểu:
- Dùng 3+ key servers với threshold 2/3
- Monitor key server health
- Fallback to backup key nếu available
- Alert team nếu servers down
Rủi ro: Logic bug cho phép unauthorized access Giảm thiểu:
- Comprehensive testing
- Audit code trước deploy
- Test với expired/revoked licenses
- Monitor failed decrypt attempts
Rủi ro: Recently created objects không query được Giảm thiểu:
- Retry với exponential backoff
- Wait 1-2 seconds sau object creation
- Handle
InvalidParametererrors gracefully
Rủi ro: Key servers rate limit requests Giảm thiểu:
- Cache decrypted keys (reuse SealClient instance)
- Batch decrypt multiple items
- Use
fetchKeys()cho multiple IDs - Design app để minimize key requests
-
Client-side AES encryption → SAI
- Không dùng Seal threshold encryption
- Backend giữ keys → security risk
-
Tự tạo SealPolicy struct → SAI
- Không có SealPolicy struct trong Seal
- Access control qua seal_approve function
-
Backend tự decrypt → SAI
- Không có key servers involvement
- Không có threshold security
-
Direct decryption → SAI
- Không verify onchain
- Không có audit trail
-
Seal SDK encryption
- Dùng
SealClient.encrypt() - Threshold encryption với key servers
- Identity-based encryption
- Dùng
-
Move function seal_approve
- Access control logic onchain
- Side-effect free verification
- Customizable policies
-
SessionKey + Transaction
- SessionKey cần user signature
- Transaction proves onchain access
- Key servers verify transaction
-
Seal SDK decryption
SealClient.decrypt()với txBytes- Key servers return shares
- Threshold reconstruction
- Automatic verification
- Viết
lora_asset.movevới LoRAAsset struct - Viết
rental_system.movevới RentalLicense - Viết
seal_integration.movevới seal_approve ⭐ - Test seal_approve với:
- Valid license
- Expired license
- Wrong LoRA
- Inactive license
- Deploy lên Sui testnet
- Lưu packageId
- Install
@mysten/sealvà@mysten/sui.js - Setup SealClient với testnet key servers
- Implement upload flow:
- Read file
- Encrypt với SealClient
- Upload encryptedObject lên Walrus
- Update Sui với blob_id
- Test end-to-end upload
- Install Seal SDK (TypeScript/Python)
- Implement license verification
- Implement SessionKey creation
- Implement seal_approve transaction building
- Implement decrypt flow:
- Fetch from Walrus
- Decrypt với SealClient
- Load LoRA
- Run inference
- Test full inference flow
- Test expired license → decrypt fail
- Test revoked license → decrypt fail
- Test no license → decrypt fail
- Test wrong user → decrypt fail
- Test concurrent requests
- Load testing với key servers
- Measure latency
- Audit seal_approve logic
- Setup Permissioned key servers
- Configure rate limits
- Setup monitoring:
- Key server health
- Decrypt success rate
- Latency metrics
- Deploy to mainnet
- Setup alerts
// ❌ BAD: Create new client per request
const client = new SealClient(...);
await client.decrypt(...);
// ✅ GOOD: Reuse client instance
const globalClient = new SealClient(...);
// Cache keys automatically
await globalClient.decrypt(...);
await globalClient.decrypt(...); // Faster if same ID// Multiple seal_approve calls trong 1 transaction
const tx = new Transaction();
for (const loraId of loraIds) {
tx.moveCall({
target: `${PACKAGE_ID}::seal_integration::seal_approve`,
arguments: [
tx.pure.vector("u8", fromHEX(loraId)),
tx.object(licenses[loraId]),
tx.object('0x6'),
],
});
}
const txBytes = await tx.build({ client, onlyTransactionKind: true });
// Fetch all keys at once
const keys = await sealClient.fetchKeys({
ids: loraIds,
txBytes,
sessionKey,
threshold: 2,
});// Store symmetric key an toàn
const { encryptedObject, key } = await sealClient.encrypt(...);
// Encrypt symmetric key với user's master key
const encryptedKey = await encryptWithUserKey(key, userMasterKey);
await secureStorage.save(loraId, encryptedKey);
// Decrypt directly với symmetric key (không cần key servers)
const decrypted = await symmetricDecrypt(encryptedObject, key);- Seal Official Docs: https://seal.mystenlabs.com/
- Seal GitHub: https://github.com/MystenLabs/seal
- Walrus Docs: https://docs.wal.app/
- Sui Move Docs: https://docs.sui.io/
- IBE Paper: Boneh-Franklin Identity-Based Encryption
-
Encryption:
- ❌ AES tự implement
- ✅ Seal SDK với IBE + threshold
-
Access Control:
- ❌ Tự quản lý SealPolicy struct
- ✅ Move function
seal_approveonchain
-
Decryption:
- ❌ Backend giữ keys và decrypt trực tiếp
- ✅ SessionKey + Transaction + Key servers
-
Security:
- ❌ Single point of failure (backend)
- ✅ Threshold (2/3 key servers)
✅ Threshold Security: Không bên nào giữ toàn bộ khóa ✅ Onchain Verification: Mọi access đều có proof ✅ Audit Trail: Immutable transaction history ✅ Flexible Policies: Custom logic trong seal_approve ✅ Decentralized: Key servers phân tán
- Deploy smart contracts với seal_approve
- Setup Seal SDK integration (frontend + backend)
- Test với Walrus testnet + Seal testnet key servers
- Optimize performance (caching, batching)
- Audit security trước production
- Monitor và iterate
Updated: 2025-10-10 Version: 2.0 - Based on Official Seal & Walrus Documentation