cifer

v0.3.1

Implement quantum-resistant encryption using the CIFER SDK (cifer-sdk npm package). Covers SDK initialization, wallet setup, secret creation, text encryption/decryption, and file encryption/decryption on any supported chain (Ethereum, Sepolia, Ternoa). Use when the user mentions CIFER, cifer-sdk, quantum-resistant encryption, ML-KEM, secret creation, or encrypted payloads/files with blockchain.

0· 1.2k·0 current·0 all-time
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Suspicious
high confidence
!
Purpose & Capability
The skill's stated purpose (integrating the cifer-sdk) matches the instructions (initializing SDK, creating secrets, encrypt/decrypt payloads and files). However the runtime instructions depend on sensitive credentials (process.env.PRIVATE_KEY) and potentially other config (WalletConnect projectId, custom RPC overrides) that the registry metadata did not declare. That omission is incongruent with the stated purpose because a wallet private key is a core requirement for transaction/signing operations described.
!
Instruction Scope
SKILL.md directs the agent to create a server-side signer from process.env.PRIVATE_KEY, send transactions, poll enclave 'blackbox' jobs, and read/write local files (readFile/writeFile). Those actions are within the functional scope of the SDK but the instructions give no guidance on secure handling of the private key (use of vaults/hardware wallets), and they reference env vars and local file access not declared in the skill metadata. The guide also instructs sending encrypted/decrypted payloads to an external endpoint (https://cifer-blackbox.ternoa.dev:3010), which is expected but requires trust of that service.
Install Mechanism
This is an instruction-only skill with no install spec. The doc rightly suggests npm install cifer-sdk (plus ethers, dotenv) — a normal, proportionate dependency for a Node.js integration. Because there is no automatic install script, nothing is silently downloaded by the platform; the user must run npm themselves.
!
Credentials
The instructions require a private key (process.env.PRIVATE_KEY) to create/send transactions and to authenticate decrypt jobs. A wallet private key grants full control of the represented account and is high-value sensitive data. The skill metadata lists no required environment variables or primary credential, so the skill both fails to declare and fails to justify requesting this sensitive secret. Other optional config (WalletConnect projectId, RPC overrides) are also referenced but undeclared.
Persistence & Privilege
The skill is not force-included (always:false) and does not request system-wide configuration changes in the instructions. It does instruct reading and writing files within the user's project (encrypt/decrypt files) which is expected for its purpose. There is no indication the skill will modify other skills' configs or request permanent platform-level privileges.
What to consider before installing
This skill appears to be a legitimate integration guide for the cifer-sdk, but it omits declaring that it needs a wallet private key and other config. Before using it: (1) Do NOT paste your wallet private key into a chat or an agent prompt. The SKILL.md expects process.env.PRIVATE_KEY — supply that only from a secure secret manager or a hardware-backed signer. (2) Verify and audit the cifer-sdk npm package and the blackbox endpoint (https://cifer-blackbox.ternoa.dev:3010) yourself—the guide will upload data to that external service for encryption/decryption jobs. (3) Prefer using delegated or ephemeral accounts, vaults, or EIP-1193 adapters (browser/hardware wallets) rather than raw private keys. (4) If you install/run code, pin package versions and run in a sandboxed/dev environment first. (5) Ask the skill author or registry maintainer to update the skill metadata to declare required env vars (e.g., PRIVATE_KEY) and to document secure key-handling recommendations; the current metadata/manifest mismatch is the primary reason this skill is flagged as suspicious.

Like a lobster shell, security has layers — review code before you run it.

latestvk979emhtxa44emzcyfwnq9swzx80n1n8
1.2kdownloads
0stars
1versions
Updated 1mo ago
v0.3.1
MIT-0

CIFER SDK — Complete Integration Guide

Overview

CIFER SDK provides quantum-resistant encryption (ML-KEM-768 + AES-256-GCM) for blockchain apps. Secrets are on-chain key pairs: public key on IPFS, private key sharded across enclaves.

Package: cifer-sdk (npm) Chains: Ethereum Mainnet (1), Sepolia (11155111), Ternoa (752025) Blackbox URL: https://cifer-blackbox.ternoa.dev:3010

For the full API reference, see reference.md.


Quick Setup

npm install cifer-sdk ethers dotenv

package.json must have "type": "module" for ESM imports.

import 'dotenv/config';
import { createCiferSdk, keyManagement, blackbox } from 'cifer-sdk';
import { Wallet, JsonRpcProvider } from 'ethers';

Step 1: Initialize SDK

const sdk = await createCiferSdk({
  blackboxUrl: 'https://cifer-blackbox.ternoa.dev:3010',
});

const chainId = 1; // Ethereum Mainnet (or 11155111 for Sepolia, 752025 for Ternoa)
const controllerAddress = sdk.getControllerAddress(chainId);
const rpcUrl = sdk.getRpcUrl(chainId);

sdk.getSupportedChainIds() returns all available chains.

Step 2: Create Wallet Signer (Server-Side)

const provider = new JsonRpcProvider(rpcUrl);
const wallet = new Wallet(process.env.PRIVATE_KEY, provider);

// Signer adapter — this is what the SDK expects
const signer = {
  async getAddress() { return wallet.address; },
  async signMessage(message) { return wallet.signMessage(message); },
};

For browser wallets, use the built-in adapter instead:

import { Eip1193SignerAdapter } from 'cifer-sdk';
const signer = new Eip1193SignerAdapter(window.ethereum);

Step 3: Create a Secret

A secret costs a fee in native token. Check balance first.

const fee = await keyManagement.getSecretCreationFee({
  chainId, controllerAddress, readClient: sdk.readClient,
});

const txIntent = keyManagement.buildCreateSecretTx({ chainId, controllerAddress, fee });

const tx = await wallet.sendTransaction({
  to: txIntent.to,
  data: txIntent.data,
  value: txIntent.value,
});
const receipt = await tx.wait();
const secretId = keyManagement.extractSecretIdFromReceipt(receipt.logs);

Step 4: Wait for Secret Sync

After creation, the enclave cluster generates keys (~30-120s on mainnet).

let ready = false;
while (!ready) {
  ready = await keyManagement.isSecretReady(
    { chainId, controllerAddress, readClient: sdk.readClient },
    secretId,
  );
  if (!ready) await new Promise(r => setTimeout(r, 5000));
}

Or read the full state:

const state = await keyManagement.getSecret(
  { chainId, controllerAddress, readClient: sdk.readClient },
  secretId,
);
// state.owner, state.delegate, state.isSyncing, state.publicKeyCid

Step 5: Encrypt Text

const encrypted = await blackbox.payload.encryptPayload({
  chainId,
  secretId,
  plaintext: 'Your secret message',
  signer,
  readClient: sdk.readClient,
  blackboxUrl: sdk.blackboxUrl,
});
// Returns: { cifer, encryptedMessage }

Step 6: Decrypt Text

Caller must be secret owner or delegate.

const decrypted = await blackbox.payload.decryptPayload({
  chainId,
  secretId,
  encryptedMessage: encrypted.encryptedMessage,
  cifer: encrypted.cifer,
  signer,
  readClient: sdk.readClient,
  blackboxUrl: sdk.blackboxUrl,
});
// Returns: { decryptedMessage }

Step 7: Encrypt File

File operations are async jobs. Works with Blob in Node.js 18+.

import { readFile, writeFile } from 'fs/promises';

const buffer = await readFile('myfile.pdf');
const blob = new Blob([buffer], { type: 'application/pdf' });

// Start encrypt job
const job = await blackbox.files.encryptFile({
  chainId, secretId, file: blob, signer,
  readClient: sdk.readClient, blackboxUrl: sdk.blackboxUrl,
});

// Poll until done
const status = await blackbox.jobs.pollUntilComplete(job.jobId, sdk.blackboxUrl, {
  intervalMs: 2000,
  maxAttempts: 120,
  onProgress: (j) => console.log(`${j.progress}%`),
});

// Download encrypted .cifer file (no auth needed for encrypt jobs)
const encBlob = await blackbox.jobs.download(job.jobId, { blackboxUrl: sdk.blackboxUrl });
await writeFile('myfile.pdf.cifer', Buffer.from(await encBlob.arrayBuffer()));

Step 8: Decrypt File

const encBuffer = await readFile('myfile.pdf.cifer');
const encBlob = new Blob([encBuffer]);

const decJob = await blackbox.files.decryptFile({
  chainId, secretId, file: encBlob, signer,
  readClient: sdk.readClient, blackboxUrl: sdk.blackboxUrl,
});

const decStatus = await blackbox.jobs.pollUntilComplete(decJob.jobId, sdk.blackboxUrl, {
  intervalMs: 2000, maxAttempts: 120,
});

// Download decrypted file (auth REQUIRED for decrypt jobs)
const decBlob = await blackbox.jobs.download(decJob.jobId, {
  blackboxUrl: sdk.blackboxUrl,
  chainId, secretId, signer, readClient: sdk.readClient,
});
await writeFile('myfile-decrypted.pdf', Buffer.from(await decBlob.arrayBuffer()));

List Existing Secrets

const secrets = await keyManagement.getSecretsByWallet(
  { chainId, controllerAddress, readClient: sdk.readClient },
  wallet.address,
);
// secrets.owned: bigint[]   — secrets you own
// secrets.delegated: bigint[] — secrets delegated to you

Delegation

Set a delegate (can decrypt but not encrypt or modify):

const txIntent = keyManagement.buildSetDelegateTx({
  chainId, controllerAddress, secretId, newDelegate: '0xDelegateAddress',
});
await wallet.sendTransaction({ to: txIntent.to, data: txIntent.data });

Remove delegation:

const txIntent = keyManagement.buildRemoveDelegationTx({
  chainId, controllerAddress, secretId,
});

Important Notes

  • Minimum SDK version: Use cifer-sdk@0.3.1 or later. Earlier versions had incorrect function selectors.
  • Payload size limit: Text encryption max ~16KB (encryptPayload). Use file encryption for larger data.
  • Block freshness: The SDK auto-retries up to 3 times if the block number becomes stale.
  • Secret sync time: ~30-60s on Ternoa, ~60-120s on Ethereum mainnet.
  • Auth for file download: Encrypt job downloads need no auth. Decrypt job downloads require signer + readClient.
  • Fee: Secret creation requires a fee in native token (e.g. ~0.0005 ETH on mainnet). Query getSecretCreationFee() first.
  • Private keys: Never expose private keys in frontend code. Use server-side signer for Node.js.

Error Handling

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

try {
  await blackbox.payload.encryptPayload({ ... });
} catch (error) {
  if (isBlockStaleError(error)) {
    // RPC returning stale blocks, SDK already retried 3x
  } else if (error instanceof SecretNotReadyError) {
    // Wait and retry
  } else if (isCiferError(error)) {
    console.error(error.code, error.message);
  }
}

Complete Minimal Example

import 'dotenv/config';
import { createCiferSdk, keyManagement, blackbox } from 'cifer-sdk';
import { Wallet, JsonRpcProvider } from 'ethers';

const sdk = await createCiferSdk({ blackboxUrl: 'https://cifer-blackbox.ternoa.dev:3010' });
const chainId = 1;
const controllerAddress = sdk.getControllerAddress(chainId);
const provider = new JsonRpcProvider(sdk.getRpcUrl(chainId));
const wallet = new Wallet(process.env.PRIVATE_KEY, provider);
const signer = {
  async getAddress() { return wallet.address; },
  async signMessage(msg) { return wallet.signMessage(msg); },
};

// Create secret
const fee = await keyManagement.getSecretCreationFee({ chainId, controllerAddress, readClient: sdk.readClient });
const txIntent = keyManagement.buildCreateSecretTx({ chainId, controllerAddress, fee });
const tx = await wallet.sendTransaction({ to: txIntent.to, data: txIntent.data, value: txIntent.value });
const receipt = await tx.wait();
const secretId = keyManagement.extractSecretIdFromReceipt(receipt.logs);

// Wait for sync
let ready = false;
while (!ready) {
  ready = await keyManagement.isSecretReady({ chainId, controllerAddress, readClient: sdk.readClient }, secretId);
  if (!ready) await new Promise(r => setTimeout(r, 5000));
}

// Encrypt & decrypt
const enc = await blackbox.payload.encryptPayload({
  chainId, secretId, plaintext: 'Hello CIFER!', signer,
  readClient: sdk.readClient, blackboxUrl: sdk.blackboxUrl,
});
const dec = await blackbox.payload.decryptPayload({
  chainId, secretId, encryptedMessage: enc.encryptedMessage, cifer: enc.cifer,
  signer, readClient: sdk.readClient, blackboxUrl: sdk.blackboxUrl,
});
console.log(dec.decryptedMessage); // "Hello CIFER!"

Comments

Loading comments...