Skip to Content
⚙️ Core SDKVault & Key Backup

Vault & Key Backup

Back up and restore MPC keyshares with password-encrypted cloud storage.

The vault module provides secure keyshare backup and recovery through the embarkAI ShareVault service. Keyshares are encrypted client-side before upload — the server never sees plaintext key material.

Configuration

import { configureVaultModule } from "@embarkai/core"; configureVaultModule({ tssUrl: "https://tss.embarkai.io", // optional override shareVaultUrl: "https://vault.embarkai.io", // optional override });

Default URLs are resolved automatically for supported chains.

The vault functions take a ServerWalletClient authenticated with your project API key:

import { createServerWalletClient } from "@embarkai/core/clients"; const client = createServerWalletClient({ apiKey: process.env.EMBARK_API_KEY!, });

Check Backup Status

Verify whether a backup exists for a user before attempting restore:

import { checkBackupExists } from "@embarkai/core"; import { createServerWalletClient } from "@embarkai/core/clients"; const client = createServerWalletClient({ apiKey: process.env.EMBARK_API_KEY! }); const { hasBackup, serviceAvailable } = await checkBackupExists( client, "user_abc123", ); if (!serviceAvailable) { console.warn("Vault service is temporarily unavailable"); } else if (hasBackup) { console.log("Backup found, ready to restore"); }

Back Up a Keyshare

import { backupToVault } from "@embarkai/core"; import type { KeyshareBackupData } from "@embarkai/core"; import { createServerWalletClient } from "@embarkai/core/clients"; const client = createServerWalletClient({ apiKey: process.env.EMBARK_API_KEY! }); const backupData: KeyshareBackupData = { userId: "user_abc123", sessionId: "session_xyz", keyshare: "...base64-encoded-keyshare...", ownerAddress: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", createdAt: Date.now(), version: "1", }; await backupToVault(client, backupData, "user-chosen-password");

Restore a Keyshare

import { restoreFromVault } from "@embarkai/core"; import { createServerWalletClient } from "@embarkai/core/clients"; const client = createServerWalletClient({ apiKey: process.env.EMBARK_API_KEY! }); const recovered = await restoreFromVault( client, "user_abc123", "user-chosen-password", ); console.log("Owner:", recovered.ownerAddress); console.log("Session:", recovered.sessionId); // recovered.keyshare is now available for signing

If the password is incorrect, restoreFromVault throws an error. There is no password reset mechanism — the encryption is client-side and the server has no access to the plaintext.

KeyshareBackupData Type

FieldTypeDescription
userIdstringUser identifier
sessionIdstringDKG session that produced this keyshare
keysharestringBase64-encoded keyshare data
ownerAddress`0x${string}`EOA address derived from the TSS public key
createdAtnumberTimestamp of keyshare creation (ms)
versionstringBackup format version

Encryption Details

All encryption happens client-side before any data leaves the device:

  1. Key Derivation — The user password is stretched using PBKDF2 with 150,000 iterations and SHA-256 to produce a Key Encryption Key (KEK).
  2. Data Encryption Key — A random 256-bit Data Encryption Key (DEK) is generated per backup.
  3. Envelope Encryption — The keyshare payload is encrypted with AES-256-GCM using the DEK. The DEK is then wrapped (encrypted) with the KEK.
  4. Storage — The encrypted envelope (wrapped DEK + ciphertext + IV + salt) is uploaded to the ShareVault. The server stores only ciphertext and cannot decrypt without the password.

This envelope encryption scheme means changing the password only requires re-wrapping the DEK, not re-encrypting the entire payload.

Usage with ServerWalletManager

ServerWalletManager provides convenient shorthand methods that handle KeyshareBackupData assembly automatically:

import { createServerWalletManager, MemoryKeyshareStorage, } from "@embarkai/core"; const manager = createServerWalletManager({ apiKey: process.env.EMBARK_API_KEY!, chainId: 994873017, storage: new MemoryKeyshareStorage(), }); // Back up a wallet's keyshare await manager.backupToVault("treasury_main", "secure-password"); // Check if a backup exists const { hasBackup } = await manager.checkBackupExists("treasury_main"); // Restore keyshare to local storage await manager.restoreFromVault("treasury_main", "secure-password");

Security Notes

  • Password strength matters. PBKDF2 slows brute-force attacks, but a weak password is still vulnerable. Enforce minimum length and complexity requirements in your UI.
  • No password recovery. The server cannot decrypt backups. If the user forgets their password, the backup is permanently inaccessible.
  • One backup per user. A new backup overwrites the previous one. Coordinate backup timing if multiple devices share the same user ID.
  • Audit restore attempts. Log failed restore attempts to detect potential brute-force attacks against user passwords.

Next Steps

  • Server Wallets — create wallets and use manager.backupToVault() shorthand
  • Authentication — set up authenticated sessions required for vault API calls
  • Bundler — submit transactions after restoring a keyshare
Last updated on