seal

For the complete documentation index, see llms.txt

For a comprehensive technical analysis and formal security proofs, see the Seal Whitepaper. The latest version (v2) incorporates the design and analysis of MPC committees for the decentralized mode key server.

Overview

Seal uses a cryptographic primitive called Identity-Based Encryption (IBE) to encrypt stored data. This design detail is abstracted away from both developers and users, as Seal does not have visibility into the data it helps secure.

An IBE scheme consists of the following algorithms:

Such a scheme is correct if for any id and m, (msk, mpk) ← Setup() and c ← Encrypt(mpk, id, m) we have Decrypt(Derive(msk, id), c) = m.

The domain of identities is not fixed and can be any string or byte array. Seal uses this property to bound onchain strings to IBE identities.

Seal consists of two main components:

Consider the following basic example for realizing time-lock encryption:

module patterns::tle;

use sui::bcs;
use sui::clock;

const ENoAccess : u64 = 1;

/////////////////////////////////////////////
/// Access control
/// The IBE identity being used: [pkg id][bcs::to_bytes(time)]
/// The following function accepts only the inner identity, i.e., [bcs::to_bytes(time)], and Seal extends it with the namespace.
entry fun seal_approve(id: vector<u8>, c: &clock::Clock) {
    // Convert the identity to u64.
    let mut prepared: BCS = bcs::new(id);
    let t = prepared.peel_u64();
    let leftovers = prepared.into_remainder_bytes();

    // Check that the time has passed and the entire identity is consumed.
    assert!((leftovers.length() == 0) && (c.timestamp_ms() >= t), ENoAccess);
}

The module controls all IBE identities that begin with its package ID PkgId. To encrypt data with a time-lock T, a user selects a key server and encrypts the data using the identity [PkgId][bcs::to_bytes(T)] and the server’s IBE master public key. Once the onchain time on Sui exceeds T, anyone can request the decryption key for the identity [PkgId][bcs::to_bytes(T)] from the Seal key server. Access control is enforced by the seal_approve function defined in the module. This function receives the requested identity (excluding the PkgId prefix) and a Clock as arguments. It returns success only if the current time is greater than or equal to T. The key server evaluates seal_approve to determine whether the derived key can be returned.

Time-lock encryption can be applied to a variety of onchain use cases, including MEV-resistant trading, secure voting, and more. For additional examples and useful implementation patterns, see Example patterns.

The framework is fully generic. Developers can define custom authorization logic within seal_approve* functions and choose which key servers to use based on their application’s needs. For example, they can use a fixed set of trusted key servers or allow users to select their preferred servers.

When you upgrade a package, it retains the same identity subdomain. To support secure upgrades, follow the recommended best practices for versioned shared objects. Specifically, version your shared objects, or create a global versioned shared object for your package. For examples, see the allowlist and subscription patterns. Keep in mind that if a package is upgradeable, the access control policy can be changed at any time by the package owner. These changes are transparent and publicly visible onchain.

Decentralization and trust model

Seal is designed to reduce centralization using a couple of mechanisms.

First, users can choose any combination of one or more key servers and use their master public keys to encrypt data. This setup supports t-out-of-n threshold encryption, which ensures:

Seal does not mandate the use of any specific key server. Instead, users can select key servers based on their own trust assumptions. Key servers can vary in security characteristics, such as running within secure enclaves or being air-gapped, and can operate across different locations and jurisdictions.

:::info

The set of key servers is not dynamic once the data is encrypted, and encrypted data cannot be changed to use a different set of servers.

:::

Second, a decentralized key server can also be implemented using an MPC committee in a t-out-of-n configuration. This committee can consist of Sui validators or any other group of participants. Users can choose to use decentralized key servers in addition to independent key servers. In this setup, the participants in the MPC committee can change over time, allowing for dynamic membership.

The security of encrypted data relies on the following assumptions:

Key server

A light server is initialized with an identity-based encryption (IBE) master secret key and has access to a trusted full node. In simple deployments, the server runs as a backend service with the secret key stored in protected storage, optionally secured using a software or hardware vault. More advanced deployments can use secure enclaves, MPC committees, or even air-gapped environments to enhance security.

The server exposes only two APIs:

See crates/key-server for the implementation of the key server.

User confirmation and sessions

Decryption keys returned from the key server are returned directly to the caller, which is typically the dApp’s web page. To ensure that dApps can access only keys explicitly approved by the user, the user must approve the key access request in their wallet. This approval is granted once per package and authorizes a session key. The session key allows the dApp to retrieve associated decryption keys for a limited time without requiring repeated user confirmations.

Cryptographic primitives

Seal is designed to support multiple identity-based encryption (IBE) schemes as Key Encapsulation Mechanisms (KEMs) and various symmetric encryption schemes as Data Encapsulation Mechanisms (DEMs). Currently supported primitives include:

Prefer AES-256-GCM for most use cases as it is faster. Use HMAC-CTR only when you require onchain decryption.

Post-quantum primitives are planned to be added in the future.

For advanced encryption schemes, use Seal as a KMS to protect the scheme’s secret key. This approach enables streaming, hardware-assisted, or chunked decryption while keeping keys out of application code.