Additional KMS root seed backup path using Seal

We are adding Seal as an independent secondary backup path for the KMS root seed.

The existing KMS recovery path remains backed by Threshold Network. Seal gives us a second recovery route with a separate key-server threshold path, enforced through a Sui Move access-control contract.

The protected value is a 64-byte KMS root seed. We store it directly as the Seal payload.

Access Control Model

Today, access control is managed by the Solidity KmsRoot contract. KmsRoot verifies TEE attestations from valid KMS root servers and uses that to gate access to recovery material.

For the Seal path, we are building the analogous access control surface in Move on Sui.

Solidity:
  KmsRoot
    verifies TEE attestations from valid KMS root servers
    gates access to KMS recovery material

Move on Sui:
  KmsRoot-equivalent package
    verifies TEE attestations from valid KMS root servers
    exposes Seal approval entrypoint
    gates Seal key release

The Move package will expose a narrowly scoped seal_approve function. Seal key servers execute or validate the approval transaction before returning key shares.

Seal Identity

The Seal identity for a backup is:

full_id = package_id || backup_id

package_id is the deployed Sui package containing the Move KmsRoot-equivalent policy. backup_id is our application-level identifier for a specific KMS backup generation.

This means access is bound to both:

  • the deployed Move policy package
  • the specific backup identity

Encryption Flow

Encryption happens inside a TEE as usual. Seal key servers do not see the blob and are not queried during encryption except indirectly through public-key metadata lookup.

input:
  package_id
  backup_id
  key_server_ids
  threshold
  kms_recovery_blob[64]

client:
  fetch key-server public keys from Sui
  Seal-encrypt kms_recovery_blob
  return EncryptedObject + recovery_key

storage:
  persist bcs(EncryptedObject)
  discard recovery_key

Seal internally uses a KEM/DEM construction. It generates a fresh symmetric content key, encrypts the 64-byte blob locally, and stores threshold-wrapped key material in the EncryptedObject.

The returned recovery_key is a local escape hatch for the generated content key. We explicitly drop it and do not log, persist, export, or colocate it with the backup artifact. Keeping it would bypass the Seal threshold/access-policy path.

Reencryption Flow

Since we wish to retain the same root seed as the current KMS, we first decrypt in a TEE using Threshold Network and reencrypt it using the encryption flow above.

The reencryption enclave will be made public for verification along with approval transactions in KmsRoot to allow it to decrypt.

Restore Flow

Restore is where Seal key servers participate.

input:
  bcs(EncryptedObject)
  SessionKey
  approval PTB calling Move seal_approve

client:
  submit fetch-key requests to Seal key servers
  key servers validate approval policy
  collect threshold key responses
  reconstruct content key locally
  decrypt 64-byte KMS recovery blob

The approval PTB proves that the caller satisfies the Move KmsRoot-equivalent policy, including valid TEE attestation checks for authorized KMS root servers.

Backup Artifact Metadata

Each stored backup artifact records:

package_id
backup_id
threshold
key_server_ids
committee aggregator URLs, if applicable
bcs(EncryptedObject)
policy/package version metadata

Security Properties

  • Seal is an additional recovery path, not a replacement for the existing threshold backup.
  • The 64-byte KMS recovery blob is never sent to Seal key servers.
  • Restore requires both Move-policy approval and threshold Seal key-server availability.
  • Access control mirrors the existing Solidity KmsRoot model, but is enforced through Sui Move.
  • The encrypted artifact is useless without satisfying the Seal approval policy.
  • We avoid custom crypto and use the normal Seal SDK decrypt path.

Implementation Notes

  • The Move package mirrors the existing Solidity KmsRoot authorization model.
  • Package and key-server configuration are pinned per backup generation.
  • The Rust client path is audited for request headers, key-server metadata validation, and recovery-key handling.
  • Integration coverage encrypts a generated 64-byte blob, drops the recovery key, restores through the approval PTB, and verifies byte equality.