@arcium-hq/client
v0.5.2
Published
Client SDK for interacting with encrypted Solana programs
Maintainers
Readme
Arcium Client SDK
The Arcium Client SDK is a TypeScript library for interacting with the Arcium Solana program, enabling secure multi-party computation on encrypted data.
Installation
npm install @arcium-hq/client
# or
yarn add @arcium-hq/client
# or
pnpm add @arcium-hq/clientQuick Start
1. Setup and Environment
import { getArciumEnv } from "@arcium-hq/client";
import * as anchor from "@coral-xyz/anchor";
// Get Arcium environment configuration
const arciumEnv = getArciumEnv();
// Setup Anchor provider
anchor.setProvider(anchor.AnchorProvider.env());
const provider = anchor.getProvider();2. Encryption Setup
To send private data for computation within Arcium, you need to encrypt it using a shared secret derived from your keypair and the Arcium MXE's public key.
Generate a client keypair:
import { x25519 } from "@arcium-hq/client";
const privateKey = x25519.utils.randomSecretKey();
const publicKey = x25519.getPublicKey(privateKey);Obtain the MXE's public key:
import { getMXEPublicKey } from "@arcium-hq/client";
// Fetch the MXE public key (handles the complex extraction logic internally)
const mxePublicKey = await getMXEPublicKey(provider, program.programId);
if (!mxePublicKey) {
throw new Error("MXE public key not set");
}Compute the shared secret and initialize cipher:
import { RescueCipher } from "@arcium-hq/client";
const sharedSecret = x25519.getSharedSecret(privateKey, mxePublicKey);
const cipher = new RescueCipher(sharedSecret);3. Encrypt and Submit Data
import { randomBytes } from "crypto";
import { deserializeLE } from "@arcium-hq/client";
// Prepare your data as BigInts
const val1 = BigInt(123);
const val2 = BigInt(456);
const plaintext = [val1, val2];
// Generate a random nonce (16 bytes)
const nonce = randomBytes(16);
// Encrypt the data
const ciphertext = cipher.encrypt(plaintext, nonce);
// Submit to your program
const computationOffset = new anchor.BN(randomBytes(8), "hex");
const sig = await program.methods
.yourComputationMethod(
computationOffset,
Array.from(ciphertext[0]),
Array.from(ciphertext[1]),
Array.from(publicKey),
new anchor.BN(deserializeLE(nonce).toString())
)
.accountsPartial({
// Account setup - see Account Helpers section
})
.rpc({ skipPreflight: true, commitment: "confirmed" });4. Track and Finalize Computation
import { awaitComputationFinalization } from "@arcium-hq/client";
// Wait for computation to complete
const finalizeSig = await awaitComputationFinalization(
provider as anchor.AnchorProvider,
computationOffset,
program.programId,
"confirmed"
);
console.log("Computation finalized:", finalizeSig);5. Decrypt Results
// Listen for program events
const event = await awaitEvent("yourResultEvent");
// Decrypt the result using the same cipher
const decrypted = cipher.decrypt([event.encryptedResult], event.nonce)[0];
console.log("Decrypted result:", decrypted);Account Helpers
The SDK provides helper functions to derive all necessary Arcium PDAs:
import {
getArciumEnv,
getMXEAccAddress,
getMempoolAccAddress,
getCompDefAccAddress,
getExecutingPoolAccAddress,
getComputationAccAddress,
getCompDefAccOffset,
getArciumAccountBaseSeed,
getArciumProgramId,
} from "@arcium-hq/client";
// Get cluster offset from environment
const arciumEnv = getArciumEnv();
// Get MXE account address (uses MXE program ID)
const mxeAccount = getMXEAccAddress(program.programId);
// Get pool addresses (use cluster offset, not program ID)
const mempoolAccount = getMempoolAccAddress(arciumEnv.arciumClusterOffset);
const executingPool = getExecutingPoolAccAddress(arciumEnv.arciumClusterOffset);
// Get computation definition address
const compDefOffset = getCompDefAccOffset("your_computation_name");
const compDefAccount = getCompDefAccAddress(
program.programId,
Buffer.from(compDefOffset).readUInt32LE()
);
// Get computation account for a specific offset (uses cluster offset)
const computationAccount = getComputationAccAddress(
arciumEnv.arciumClusterOffset,
computationOffset
);Circuit Management
Upload a Circuit
import { uploadCircuit } from "@arcium-hq/client";
import * as fs from "fs";
const rawCircuit = fs.readFileSync("build/your_circuit.arcis");
await uploadCircuit(
provider as anchor.AnchorProvider,
"your_circuit_name",
program.programId,
rawCircuit,
true // use raw circuit
);Finalize Computation Definition
import { buildFinalizeCompDefTx } from "@arcium-hq/client";
const finalizeTx = await buildFinalizeCompDefTx(
provider as anchor.AnchorProvider,
Buffer.from(compDefOffset).readUInt32LE(),
program.programId
);
// Set blockhash and sign
const latestBlockhash = await provider.connection.getLatestBlockhash();
finalizeTx.recentBlockhash = latestBlockhash.blockhash;
finalizeTx.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;
finalizeTx.sign(owner);
// Send transaction
await provider.sendAndConfirm(finalizeTx);API Reference
- API Reference - Complete API documentation
- Developer Docs - Guides and tutorials
- Examples - Code examples
