CIFER SDK - Quantum-Resistant Blockchain Encryption
Skill for AI Agents | Enable quantum-resistant encryption in blockchain applications using the CIFER SDK.
Overview
CIFER (Cryptographic Infrastructure for Encrypted Records) SDK provides quantum-resistant encryption for blockchain applications. This skill enables AI agents to implement secure data encryption, secret management, and on-chain commitments using post-quantum cryptography.
Key Capabilities
- Quantum-Resistant Encryption: ML-KEM-768 (NIST standardized) key encapsulation
- Multi-Chain Support: Automatic chain discovery and configuration
- Wallet Agnostic: Works with MetaMask, WalletConnect, Coinbase, Thirdweb, and custom signers
- File Encryption: Async job system for large file encryption/decryption
- On-Chain Commitments: Store encrypted data references on-chain with log-based retrieval
- Transaction Intents: Non-custodial pattern - you control transaction execution
When to Use This Skill
Use the CIFER SDK when you need to:
- Encrypt sensitive data with quantum-resistant algorithms
- Store encrypted records on blockchain
- Manage encryption keys with owner/delegate authorization
- Encrypt files larger than 16KB using the job system
- Build applications requiring post-quantum security
Installation
npm install cifer-sdk
# or
yarn add cifer-sdk
# or
pnpm add cifer-sdk
Requirements: Node.js 18.0+, TypeScript 5.0+ (recommended)
Quick Start
import { createCiferSdk, Eip1193SignerAdapter, blackbox } from 'cifer-sdk';
// 1. Initialize SDK with auto-discovery
const sdk = await createCiferSdk({
blackboxUrl: 'https://blackbox.cifer.network',
});
// 2. Connect wallet (browser)
const signer = new Eip1193SignerAdapter(window.ethereum);
// 3. Encrypt data
const encrypted = await blackbox.payload.encryptPayload({
chainId: 752025,
secretId: 123n,
plaintext: 'My secret message',
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
// 4. Decrypt data
const decrypted = await blackbox.payload.decryptPayload({
chainId: 752025,
secretId: 123n,
encryptedMessage: encrypted.encryptedMessage,
cifer: encrypted.cifer,
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
console.log(decrypted.decryptedMessage); // 'My secret message'
Core Concepts
Secrets
A secret is the core primitive in CIFER. Each secret represents an ML-KEM-768 key pair:
| Property | Description |
|---|---|
owner | Address that can transfer, set delegate, and decrypt |
delegate | Address that can decrypt only (zero address if none) |
isSyncing | true while key generation is in progress |
clusterId | Which enclave cluster holds the private key shards |
secretType | 1 = ML-KEM-768 (standard) |
publicKeyCid | IPFS CID of public key (empty if syncing) |
Lifecycle: Creation → Syncing (~30-60s) → Ready
Authorization Model
| Role | Capabilities |
|---|---|
| Owner | Encrypt, decrypt, transfer, set delegate |
| Delegate | Decrypt only |
Encryption Model
CIFER uses hybrid encryption:
- ML-KEM-768: Post-quantum key encapsulation (1088-byte ciphertext)
- AES-256-GCM: Symmetric encryption for actual data
Output format:
cifer: 1104 bytes (ML-KEM ciphertext + tag)encryptedMessage: Variable length (max 16KB)
Transaction Intents
The SDK returns transaction intents instead of executing transactions:
interface TxIntent {
chainId: number;
to: Address;
data: Hex;
value?: bigint;
}
Execute with any wallet library (ethers, wagmi, viem).
API Reference
SDK Initialization
With Discovery (Recommended)
const sdk = await createCiferSdk({
blackboxUrl: 'https://blackbox.cifer.network',
});
sdk.getSupportedChainIds(); // [752025, 11155111, ...]
sdk.getControllerAddress(752025); // '0x...'
sdk.getRpcUrl(752025); // 'https://...'
With Overrides
const sdk = await createCiferSdk({
blackboxUrl: 'https://blackbox.cifer.network',
chainOverrides: {
752025: {
rpcUrl: 'https://my-private-rpc.example.com',
secretsControllerAddress: '0x...',
},
},
});
Synchronous (No Discovery)
import { createCiferSdkSync, RpcReadClient } from 'cifer-sdk';
const readClient = new RpcReadClient({
rpcUrlByChainId: {
752025: 'https://mainnet.ternoa.network',
},
});
const sdk = createCiferSdkSync({
blackboxUrl: 'https://blackbox.cifer.network',
readClient,
chainOverrides: {
752025: {
rpcUrl: 'https://mainnet.ternoa.network',
secretsControllerAddress: '0x...',
},
},
});
Wallet Integration
All wallets must implement the SignerAdapter interface:
interface SignerAdapter {
getAddress(): Promise<string>;
signMessage(message: string): Promise<string>;
sendTransaction?(txRequest: TxIntent): Promise<TxExecutionResult>;
}
MetaMask
import { Eip1193SignerAdapter } from 'cifer-sdk';
await window.ethereum.request({ method: 'eth_requestAccounts' });
const signer = new Eip1193SignerAdapter(window.ethereum);
WalletConnect v2
import { EthereumProvider } from '@walletconnect/ethereum-provider';
const provider = await EthereumProvider.init({
projectId: 'YOUR_WALLETCONNECT_PROJECT_ID',
chains: [752025],
showQrModal: true,
});
await provider.connect();
const signer = new Eip1193SignerAdapter(provider);
Private Key (Server-Side)
import { Wallet } from 'ethers';
const wallet = new Wallet(process.env.PRIVATE_KEY);
const signer = {
async getAddress() { return wallet.address; },
async signMessage(message) { return wallet.signMessage(message); },
};
wagmi (React)
import { useAccount, useConnectorClient } from 'wagmi';
function useCiferSigner() {
const { address, isConnected } = useAccount();
const { data: connectorClient } = useConnectorClient();
const getSigner = async () => {
if (!isConnected || !connectorClient) {
throw new Error('Wallet not connected');
}
const provider = await connectorClient.transport;
return new Eip1193SignerAdapter(provider);
};
return { getSigner, address, isConnected };
}
keyManagement Namespace
Interact with the SecretsController contract for secret management.
Read Operations
// Get secret creation fee
const fee = await keyManagement.getSecretCreationFee({
chainId: 752025,
controllerAddress: sdk.getControllerAddress(752025),
readClient: sdk.readClient,
});
// Get secret state
const state = await keyManagement.getSecret(params, 123n);
// Returns: { owner, delegate, isSyncing, clusterId, secretType, publicKeyCid }
// Check if secret is ready
const ready = await keyManagement.isSecretReady(params, 123n);
// Check authorization
const canDecrypt = await keyManagement.isAuthorized(params, 123n, '0x...');
// Get secrets by wallet
const secrets = await keyManagement.getSecretsByWallet(params, '0xUser...');
// Returns: { owned: bigint[], delegated: bigint[] }
Transaction Builders
// Create a new secret
const fee = await keyManagement.getSecretCreationFee(params);
const txIntent = keyManagement.buildCreateSecretTx({
chainId: 752025,
controllerAddress: sdk.getControllerAddress(752025),
fee,
});
// Set delegate
const txIntent = keyManagement.buildSetDelegateTx({
chainId: 752025,
controllerAddress: sdk.getControllerAddress(752025),
secretId: 123n,
newDelegate: '0xDelegate...',
});
// Remove delegate
const txIntent = keyManagement.buildRemoveDelegationTx({ ... });
// Transfer ownership (irreversible!)
const txIntent = keyManagement.buildTransferSecretTx({
chainId: 752025,
controllerAddress: sdk.getControllerAddress(752025),
secretId: 123n,
newOwner: '0xNewOwner...',
});
Event Parsing
const receipt = await provider.waitForTransaction(hash);
const secretId = keyManagement.extractSecretIdFromReceipt(receipt.logs);
blackbox.payload Namespace
Encrypt and decrypt short messages (< 16KB).
Encrypt
const encrypted = await blackbox.payload.encryptPayload({
chainId: 752025,
secretId: 123n,
plaintext: 'My secret message',
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
outputFormat: 'hex', // or 'base64'
});
// Returns: { cifer: string, encryptedMessage: string }
Decrypt
const decrypted = await blackbox.payload.decryptPayload({
chainId: 752025,
secretId: 123n,
encryptedMessage: encrypted.encryptedMessage,
cifer: encrypted.cifer,
signer, // Must be owner or delegate
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
inputFormat: 'hex',
});
// Returns: { decryptedMessage: string }
blackbox.files Namespace
Encrypt and decrypt large files using async jobs.
// Start encryption job
const job = await blackbox.files.encryptFile({
chainId: 752025,
secretId: 123n,
file: myFile,
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
// Returns: { jobId: string, message: string }
// Start decryption job
const job = await blackbox.files.decryptFile({ ... });
// Decrypt from existing encrypt job
const job = await blackbox.files.decryptExistingFile({
chainId: 752025,
secretId: 123n,
encryptJobId: previousJobId,
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
blackbox.jobs Namespace
Manage async file jobs.
// Get job status
const status = await blackbox.jobs.getStatus(jobId, sdk.blackboxUrl);
// Returns: { id, type, status, progress, secretId, chainId, ... }
// Poll until complete
const finalStatus = await blackbox.jobs.pollUntilComplete(
jobId,
sdk.blackboxUrl,
{
intervalMs: 2000,
maxAttempts: 120,
onProgress: (job) => console.log(`Progress: ${job.progress}%`),
}
);
// Download result (encrypt jobs: no auth, decrypt jobs: auth required)
const blob = await blackbox.jobs.download(jobId, {
blackboxUrl: sdk.blackboxUrl,
// For decrypt jobs, also provide:
chainId: 752025,
secretId: 123n,
signer,
readClient: sdk.readClient,
});
// List jobs for wallet
const result = await blackbox.jobs.list({
chainId: 752025,
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
// Get data consumption stats
const stats = await blackbox.jobs.dataConsumption({ ... });
commitments Namespace
Store and retrieve encrypted data on-chain.
// Check if commitment exists
const exists = await commitments.ciferDataExists(params, dataId);
// Get metadata
const metadata = await commitments.getCIFERMetadata(params, dataId);
// Returns: { secretId, storedAtBlock, ciferHash, encryptedMessageHash }
// Fetch encrypted data from logs
const data = await commitments.fetchCommitmentFromLogs({
chainId: 752025,
contractAddress: '0x...',
dataId: dataKey,
storedAtBlock: metadata.storedAtBlock,
readClient: sdk.readClient,
});
// Returns: { cifer, encryptedMessage, ciferHash, encryptedMessageHash }
// Verify integrity
const result = commitments.verifyCommitmentIntegrity(data, metadata);
// Build store transaction
const txIntent = commitments.buildStoreCommitmentTx({
chainId: 752025,
contractAddress: '0xYourContract...',
storeFunction: {
type: 'function',
name: 'store',
inputs: [
{ name: 'key', type: 'bytes32' },
{ name: 'encryptedMessage', type: 'bytes' },
{ name: 'cifer', type: 'bytes' },
],
},
args: {
key: dataKey,
secretId: 123n,
encryptedMessage: encrypted.encryptedMessage,
cifer: encrypted.cifer,
},
});
Constants:
CIFER_ENVELOPE_BYTES = 1104(fixed cifer size)MAX_PAYLOAD_BYTES = 16384(16KB max payload)
flows Namespace
High-level orchestrated operations.
Flow Context
const ctx = {
signer: SignerAdapter,
readClient: ReadClient,
blackboxUrl: string,
chainId: number,
controllerAddress?: Address,
txExecutor?: (intent: TxIntent) => Promise<TxExecutionResult>,
pollingStrategy?: { intervalMs: number, maxAttempts: number },
logger?: (message: string) => void,
abortSignal?: AbortSignal,
};
Create Secret and Wait
const result = await flows.createSecretAndWaitReady({
...ctx,
controllerAddress: sdk.getControllerAddress(752025),
txExecutor: async (intent) => {
const hash = await wallet.sendTransaction(intent);
return { hash, waitReceipt: () => provider.waitForTransaction(hash) };
},
});
if (result.success) {
console.log('Secret ID:', result.data.secretId);
console.log('Public Key CID:', result.data.state.publicKeyCid);
}
Encrypt and Prepare Commit
const result = await flows.encryptThenPrepareCommitTx(ctx, {
secretId: 123n,
plaintext: 'My secret data',
key: dataKey,
commitmentContract: '0x...',
});
if (result.success) {
await wallet.sendTransaction(result.data.txIntent);
}
Retrieve and Decrypt from Logs
const result = await flows.retrieveFromLogsThenDecrypt(ctx, {
secretId: 123n,
dataId: dataKey,
commitmentContract: '0x...',
});
if (result.success) {
console.log('Decrypted:', result.data.decryptedMessage);
}
File Flows
// Encrypt file flow
const result = await flows.encryptFileJobFlow(ctx, {
secretId: 123n,
file: myFile,
});
// Returns: { jobId, job, encryptedFile: Blob }
// Decrypt file flow
const result = await flows.decryptFileJobFlow(ctx, {
secretId: 123n,
file: ciferFile,
});
// Returns: { jobId, job, decryptedFile: Blob }
Error Handling
All SDK errors extend CiferError with typed subclasses:
CiferError
├── ConfigError
│ ├── DiscoveryError
│ └── ChainNotSupportedError
├── AuthError
│ ├── SignatureError
│ ├── BlockStaleError
│ └── SignerMismatchError
├── BlackboxError
│ ├── EncryptionError
│ ├── DecryptionError
│ ├── JobError
│ └── SecretNotReadyError
├── KeyManagementError
│ ├── SecretNotFoundError
│ └── NotAuthorizedError
├── CommitmentsError
│ ├── CommitmentNotFoundError
│ ├── IntegrityError
│ ├── InvalidCiferSizeError
│ └── PayloadTooLargeError
└── FlowError
├── FlowAbortedError
└── FlowTimeoutError
Type Guards
import {
isCiferError,
isBlockStaleError,
isSecretNotReadyError,
} from 'cifer-sdk';
Error Handling Example
try {
await blackbox.payload.encryptPayload({ ... });
} catch (error) {
if (isBlockStaleError(error)) {
console.log('RPC returning stale blocks');
} else if (error instanceof SecretNotReadyError) {
console.log('Wait for secret to sync');
} else if (error instanceof SecretNotFoundError) {
console.log('Secret not found:', error.secretId);
} else if (isCiferError(error)) {
console.log('CIFER error:', error.code, error.message);
} else {
throw error;
}
}
Common Scenarios
| Error | Cause | Solution |
|---|---|---|
| "Block number is too old" | RPC issues | SDK auto-retries 3x; check RPC reliability |
| "Secret is syncing" | Key generation in progress | Wait 30-60s; use isSecretReady() |
| "Signature verification failed" | Wrong signing method | Use EIP-191 personal_sign |
| "Not authorized" | Not owner/delegate | Check with isAuthorized() |
Complete Examples
Browser: Encrypt/Decrypt Message
import { createCiferSdk, Eip1193SignerAdapter, blackbox } from 'cifer-sdk';
async function encryptDecryptExample() {
const sdk = await createCiferSdk({
blackboxUrl: 'https://blackbox.cifer.network',
});
const signer = new Eip1193SignerAdapter(window.ethereum);
const chainId = 752025;
const secretId = 123n;
// Encrypt
const encrypted = await blackbox.payload.encryptPayload({
chainId,
secretId,
plaintext: 'Hello, CIFER!',
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
// Decrypt
const decrypted = await blackbox.payload.decryptPayload({
chainId,
secretId,
encryptedMessage: encrypted.encryptedMessage,
cifer: encrypted.cifer,
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
console.log('Decrypted:', decrypted.decryptedMessage);
}
Node.js Server-Side
import { createCiferSdk, RpcReadClient, blackbox } from 'cifer-sdk';
import { Wallet } from 'ethers';
async function serverSideExample() {
const readClient = new RpcReadClient({
rpcUrlByChainId: {
752025: 'https://mainnet.ternoa.network',
},
});
const sdk = await createCiferSdk({
blackboxUrl: 'https://blackbox.cifer.network',
readClient,
});
const wallet = new Wallet(process.env.PRIVATE_KEY);
const signer = {
async getAddress() { return wallet.address; },
async signMessage(message) { return wallet.signMessage(message); },
};
const encrypted = await blackbox.payload.encryptPayload({
chainId: 752025,
secretId: 123n,
plaintext: 'Server-side encryption',
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
console.log('Encrypted on server:', encrypted);
}
File Encryption with Progress
import { createCiferSdk, Eip1193SignerAdapter, blackbox } from 'cifer-sdk';
async function fileEncryptionExample() {
const sdk = await createCiferSdk({
blackboxUrl: 'https://blackbox.cifer.network',
});
const signer = new Eip1193SignerAdapter(window.ethereum);
const file = document.getElementById('fileInput').files[0];
// Start job
const job = await blackbox.files.encryptFile({
chainId: 752025,
secretId: 123n,
file,
signer,
readClient: sdk.readClient,
blackboxUrl: sdk.blackboxUrl,
});
// Poll with progress
const finalStatus = await blackbox.jobs.pollUntilComplete(
job.jobId,
sdk.blackboxUrl,
{
onProgress: (status) => console.log(`Progress: ${status.progress}%`),
}
);
if (finalStatus.status === 'completed') {
const encryptedBlob = await blackbox.jobs.download(job.jobId, {
blackboxUrl: sdk.blackboxUrl,
});
// Download file
const url = URL.createObjectURL(encryptedBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'encrypted.cifer';
a.click();
}
}
Type Definitions
type Address = `0x${string}`;
type Bytes32 = `0x${string}`;
type Hex = `0x${string}`;
type ChainId = number;
type SecretId = bigint;
type OutputFormat = 'hex' | 'base64';
type JobStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'expired';
type JobType = 'encrypt' | 'decrypt';
interface SecretState {
owner: Address;
delegate: Address;
isSyncing: boolean;
clusterId: number;
secretType: number;
publicKeyCid: string;
}
interface JobInfo {
id: string;
type: JobType;
status: JobStatus;
progress: number;
secretId: number;
chainId: ChainId;
createdAt: number;
completedAt?: number;
error?: string;
resultFileName?: string;
ttl: number;
originalSize?: number;
}
interface FlowResult<T> {
success: boolean;
plan: FlowPlan;
data?: T;
error?: Error;
receipts?: TransactionReceipt[];
}
Resources
- npm: https://www.npmjs.com/package/cifer-sdk
- GitHub: https://github.com/cifer-security/cifer-sdk
- Blackbox API:
https://blackbox.cifer.network - Supported Chain: Ternoa (752025)
This skill enables AI agents to implement quantum-resistant encryption in blockchain applications using the CIFER SDK.