文件预览

skill.md

查看 Cifer SDK 技能包中的文件内容。

文件内容

skill.md

# 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

```bash
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

```typescript
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:
1. **ML-KEM-768**: Post-quantum key encapsulation (1088-byte ciphertext)
2. **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:

```typescript
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)

```typescript
const sdk = await createCiferSdk({
  blackboxUrl: 'https://blackbox.cifer.network',
});

sdk.getSupportedChainIds(); // [752025, 11155111, ...]
sdk.getControllerAddress(752025); // '0x...'
sdk.getRpcUrl(752025); // 'https://...'
```

#### With Overrides

```typescript
const sdk = await createCiferSdk({
  blackboxUrl: 'https://blackbox.cifer.network',
  chainOverrides: {
    752025: {
      rpcUrl: 'https://my-private-rpc.example.com',
      secretsControllerAddress: '0x...',
    },
  },
});
```

#### Synchronous (No Discovery)

```typescript
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:

```typescript
interface SignerAdapter {
  getAddress(): Promise<string>;
  signMessage(message: string): Promise<string>;
  sendTransaction?(txRequest: TxIntent): Promise<TxExecutionResult>;
}
```

#### MetaMask

```typescript
import { Eip1193SignerAdapter } from 'cifer-sdk';

await window.ethereum.request({ method: 'eth_requestAccounts' });
const signer = new Eip1193SignerAdapter(window.ethereum);
```

#### WalletConnect v2

```typescript
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)

```typescript
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)

```typescript
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

```typescript
// 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

```typescript
// 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

```typescript
const receipt = await provider.waitForTransaction(hash);
const secretId = keyManagement.extractSecretIdFromReceipt(receipt.logs);
```

---

### blackbox.payload Namespace

Encrypt and decrypt short messages (< 16KB).

#### Encrypt

```typescript
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

```typescript
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.

```typescript
// 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.

```typescript
// 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.

```typescript
// 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

```typescript
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

```typescript
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

```typescript
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

```typescript
const result = await flows.retrieveFromLogsThenDecrypt(ctx, {
  secretId: 123n,
  dataId: dataKey,
  commitmentContract: '0x...',
});

if (result.success) {
  console.log('Decrypted:', result.data.decryptedMessage);
}
```

#### File Flows

```typescript
// 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

```typescript
import {
  isCiferError,
  isBlockStaleError,
  isSecretNotReadyError,
} from 'cifer-sdk';
```

### Error Handling Example

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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](https://www.npmjs.com/package/cifer-sdk)
- **GitHub**: [https://github.com/cifer-security/cifer-sdk](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.*